--- a/.hgtags-top-repo Mon Feb 22 09:02:14 2016 +0100
+++ b/.hgtags-top-repo Wed Jul 05 21:21:58 2017 +0200
@@ -348,3 +348,4 @@
47d6462e514b2097663305a57d9c844c15d5b609 jdk-9+103
9a38f8b4ba220708db198d08d82fd2144a64777d jdk-9+104
be58b02c11f90b88c67e4d0e2cb5e4cf2d9b3c57 jdk-9+105
+54575d8783b3a39a2d710c28cda675d44261f9d9 jdk-9+106
--- a/hotspot/.hgtags Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/.hgtags Wed Jul 05 21:21:58 2017 +0200
@@ -508,3 +508,4 @@
c5f55130b1b69510d9a6f4a3105b58e21cd7ffe1 jdk-9+103
534c50395957c6025fb6627e93b35756f8d48a08 jdk-9+104
266fa9bb5297bf02cb2a7b038b10a109817d2b48 jdk-9+105
+7232de4c17c37f60aecec4f3191090bd3d41d334 jdk-9+106
--- a/hotspot/.mx.jvmci/suite.py Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/.mx.jvmci/suite.py Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
suite = {
- "mxversion" : "5.6.11",
+ "mxversion" : "5.6.16",
"name" : "jvmci",
"url" : "http://openjdk.java.net/projects/graal",
"developer" : {
--- a/hotspot/make/bsd/makefiles/gcc.make Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/make/bsd/makefiles/gcc.make Wed Jul 05 21:21:58 2017 +0200
@@ -256,7 +256,7 @@
# Compiler warnings are treated as errors
ifneq ($(COMPILER_WARNINGS_FATAL),false)
- WARNINGS_ARE_ERRORS = -Werror
+ WARNINGS_ARE_ERRORS ?= -Werror
endif
ifeq ($(USE_CLANG), true)
--- a/hotspot/make/linux/makefiles/gcc.make Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/make/linux/makefiles/gcc.make Wed Jul 05 21:21:58 2017 +0200
@@ -203,7 +203,7 @@
endif
# Compiler warnings are treated as errors
-WARNINGS_ARE_ERRORS = -Werror
+WARNINGS_ARE_ERRORS ?= -Werror
ifeq ($(USE_CLANG), true)
# However we need to clean the code up before we can unrestrictedly enable this option with Clang
--- a/hotspot/make/solaris/makefiles/adlc.make Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/make/solaris/makefiles/adlc.make Wed Jul 05 21:21:58 2017 +0200
@@ -66,17 +66,21 @@
CXXFLAGS += -DASSERT
ifndef USE_GCC
- # We need libCstd.so for adlc
+ # We need libCstd.so for adlc
CFLAGS += -library=Cstd -g
LFLAGS += -library=Cstd -g
endif
# CFLAGS_WARN holds compiler options to suppress/enable warnings.
+CFLAGS_WARN = +w
# Compiler warnings are treated as errors
ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 509), 1)
- CFLAGS_WARN = +w -errwarn
+ WARNINGS_ARE_ERRORS ?= -xwe
endif
-# When using compiler version 5.13 (Solaris Studio 12.4), calls to explicitly
+
+CFLAGS_WARN += $(WARNINGS_ARE_ERRORS)
+
+# When using compiler version 5.13 (Solaris Studio 12.4), calls to explicitly
# instantiated template functions trigger this warning when +w is active.
ifeq ($(shell expr $(COMPILER_REV_NUMERIC) \>= 513), 1)
CFLAGS_WARN += -erroff=notemsource
--- a/hotspot/make/solaris/makefiles/gcc.make Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/make/solaris/makefiles/gcc.make Wed Jul 05 21:21:58 2017 +0200
@@ -117,7 +117,7 @@
# Compiler warnings are treated as errors
-WARNINGS_ARE_ERRORS = -Werror
+WARNINGS_ARE_ERRORS ?= -Werror
# Enable these warnings. See 'info gcc' about details on these options
WARNING_FLAGS = -Wpointer-arith -Wconversion -Wsign-compare -Wundef -Wformat=2
--- a/hotspot/make/solaris/makefiles/sparcWorks.make Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/make/solaris/makefiles/sparcWorks.make Wed Jul 05 21:21:58 2017 +0200
@@ -145,7 +145,8 @@
CFLAGS += -DDONT_USE_PRECOMPILED_HEADER
# Compiler warnings are treated as errors
-CFLAGS_WARN = -xwe
+WARNINGS_ARE_ERRORS ?= -xwe
+CFLAGS_WARN = $(WARNINGS_ARE_ERRORS)
################################################
# Begin current (>=5.9) Forte compiler options #
--- a/hotspot/src/cpu/aarch64/vm/aarch64.ad Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad Wed Jul 05 21:21:58 2017 +0200
@@ -14928,7 +14928,22 @@
ins_pipe(pipe_class_memory);
%}
-instruct array_equals(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result,
+instruct array_equalsB(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result,
+ iRegP_R10 tmp, rFlagsReg cr)
+%{
+ predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL);
+ match(Set result (AryEq ary1 ary2));
+ effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, KILL cr);
+
+ format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %}
+ ins_encode %{
+ __ byte_arrays_equals($ary1$$Register, $ary2$$Register,
+ $result$$Register, $tmp$$Register);
+ %}
+ ins_pipe(pipe_class_memory);
+%}
+
+instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result,
iRegP_R10 tmp, rFlagsReg cr)
%{
predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
--- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -40,11 +40,7 @@
define_pd_global(bool, TrapBasedNullChecks, false);
define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast
-#if defined(COMPILER2) || INCLUDE_JVMCI
define_pd_global(intx, CodeEntryAlignment, 64);
-#else
-define_pd_global(intx, CodeEntryAlignment, 16);
-#endif // COMPILER2
define_pd_global(intx, OptoLoopAlignment, 16);
define_pd_global(intx, InlineFrequencyCount, 100);
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -127,7 +127,10 @@
Instruction_aarch64::extract(insn2, 4, 0)) {
// movk #imm16<<32
Instruction_aarch64::patch(branch + 4, 20, 5, (uint64_t)target >> 32);
- offset &= (1<<20)-1;
+ long dest = ((long)target & 0xffffffffL) | ((long)branch & 0xffff00000000L);
+ long pc_page = (long)branch >> 12;
+ long adr_page = (long)dest >> 12;
+ offset = adr_page - pc_page;
instructions = 2;
}
}
@@ -898,23 +901,18 @@
"caller must use same register for non-constant itable index as for method");
// Compute start of first itableOffsetEntry (which is at the end of the vtable)
- int vtable_base = InstanceKlass::vtable_start_offset() * wordSize;
+ int vtable_base = in_bytes(Klass::vtable_start_offset());
int itentry_off = itableMethodEntry::method_offset_in_bytes();
int scan_step = itableOffsetEntry::size() * wordSize;
- int vte_size = vtableEntry::size() * wordSize;
+ int vte_size = vtableEntry::size_in_bytes();
assert(vte_size == wordSize, "else adjust times_vte_scale");
- ldrw(scan_temp, Address(recv_klass, InstanceKlass::vtable_length_offset() * wordSize));
+ ldrw(scan_temp, Address(recv_klass, Klass::vtable_length_offset()));
// %%% Could store the aligned, prescaled offset in the klassoop.
// lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));
lea(scan_temp, Address(recv_klass, scan_temp, Address::lsl(3)));
add(scan_temp, scan_temp, vtable_base);
- if (HeapWordsPerLong > 1) {
- // Round up to align_object_offset boundary
- // see code for instanceKlass::start_of_itable!
- round_to(scan_temp, BytesPerLong);
- }
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
@@ -963,7 +961,7 @@
void MacroAssembler::lookup_virtual_method(Register recv_klass,
RegisterOrConstant vtable_index,
Register method_result) {
- const int base = InstanceKlass::vtable_start_offset() * wordSize;
+ const int base = in_bytes(Klass::vtable_start_offset());
assert(vtableEntry::size() * wordSize == 8,
"adjust the scaling in the code below");
int vtable_offset_in_bytes = base + vtableEntry::method_offset_in_bytes();
@@ -3998,11 +3996,12 @@
if (offset_high >= -(1<<20) && offset_low < (1<<20)) {
_adrp(reg1, dest.target());
} else {
- unsigned long pc_page = (unsigned long)pc() >> 12;
- long offset = dest_page - pc_page;
- offset = (offset & ((1<<20)-1)) << 12;
- _adrp(reg1, pc()+offset);
- movk(reg1, (unsigned long)dest.target() >> 32, 32);
+ unsigned long target = (unsigned long)dest.target();
+ unsigned long adrp_target
+ = (target & 0xffffffffUL) | ((unsigned long)pc() & 0xffff00000000UL);
+
+ _adrp(reg1, (address)adrp_target);
+ movk(reg1, target >> 32, 32);
}
byte_offset = (unsigned long)dest.target() & 0xfff;
}
@@ -4557,6 +4556,82 @@
BLOCK_COMMENT("} string_equals");
}
+
+void MacroAssembler::byte_arrays_equals(Register ary1, Register ary2,
+ Register result, Register tmp1)
+{
+ Register cnt1 = rscratch1;
+ Register cnt2 = rscratch2;
+ Register tmp2 = rscratch2;
+
+ Label SAME, DIFFER, NEXT, TAIL07, TAIL03, TAIL01;
+
+ int length_offset = arrayOopDesc::length_offset_in_bytes();
+ int base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE);
+
+ BLOCK_COMMENT("byte_arrays_equals {");
+
+ // different until proven equal
+ mov(result, false);
+
+ // same array?
+ cmp(ary1, ary2);
+ br(Assembler::EQ, SAME);
+
+ // ne if either null
+ cbz(ary1, DIFFER);
+ cbz(ary2, DIFFER);
+
+ // lengths ne?
+ ldrw(cnt1, Address(ary1, length_offset));
+ ldrw(cnt2, Address(ary2, length_offset));
+ cmp(cnt1, cnt2);
+ br(Assembler::NE, DIFFER);
+
+ lea(ary1, Address(ary1, base_offset));
+ lea(ary2, Address(ary2, base_offset));
+
+ subs(cnt1, cnt1, 8);
+ br(LT, TAIL07);
+
+ BIND(NEXT);
+ ldr(tmp1, Address(post(ary1, 8)));
+ ldr(tmp2, Address(post(ary2, 8)));
+ subs(cnt1, cnt1, 8);
+ eor(tmp1, tmp1, tmp2);
+ cbnz(tmp1, DIFFER);
+ br(GE, NEXT);
+
+ BIND(TAIL07); // 0-7 bytes left, cnt1 = #bytes left - 4
+ tst(cnt1, 0b100);
+ br(EQ, TAIL03);
+ ldrw(tmp1, Address(post(ary1, 4)));
+ ldrw(tmp2, Address(post(ary2, 4)));
+ cmp(tmp1, tmp2);
+ br(NE, DIFFER);
+
+ BIND(TAIL03); // 0-3 bytes left, cnt1 = #bytes left - 4
+ tst(cnt1, 0b10);
+ br(EQ, TAIL01);
+ ldrh(tmp1, Address(post(ary1, 2)));
+ ldrh(tmp2, Address(post(ary2, 2)));
+ cmp(tmp1, tmp2);
+ br(NE, DIFFER);
+ BIND(TAIL01); // 0-1 byte left
+ tst(cnt1, 0b01);
+ br(EQ, SAME);
+ ldrb(tmp1, ary1);
+ ldrb(tmp2, ary2);
+ cmp(tmp1, tmp2);
+ br(NE, DIFFER);
+
+ BIND(SAME);
+ mov(result, true);
+ BIND(DIFFER); // result already set
+
+ BLOCK_COMMENT("} byte_arrays_equals");
+}
+
// Compare char[] arrays aligned to 4 bytes
void MacroAssembler::char_arrays_equals(Register ary1, Register ary2,
Register result, Register tmp1)
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1191,6 +1191,8 @@
Register tmp1);
void char_arrays_equals(Register ary1, Register ary2,
Register result, Register tmp1);
+ void byte_arrays_equals(Register ary1, Register ary2,
+ Register result, Register tmp1);
void encode_iso_array(Register src, Register dst,
Register len, Register result,
FloatRegister Vtmp1, FloatRegister Vtmp2,
--- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -786,12 +786,19 @@
int offset;
const Register t0 = r3, t1 = r4, t2 = r5, t3 = r6,
t4 = r7, t5 = r10, t6 = r11, t7 = r12;
+ const Register stride = r13;
assert_different_registers(rscratch1, t0, t1, t2, t3, t4, t5, t6, t7);
assert_different_registers(s, d, count, rscratch1);
Label again, large, small;
- __ align(6);
+ const char *stub_name;
+ if (direction == copy_forwards)
+ stub_name = "foward_copy_longs";
+ else
+ stub_name = "backward_copy_longs";
+ StubCodeMark mark(this, "StubRoutines", stub_name);
+ __ align(CodeEntryAlignment);
__ bind(start);
__ cmp(count, 8);
__ br(Assembler::LO, small);
@@ -836,7 +843,7 @@
__ ret(lr);
- __ align(6);
+ __ align(CodeEntryAlignment);
__ bind(large);
// Fill 8 registers
@@ -845,10 +852,18 @@
__ ldp(t4, t5, Address(s, 6 * unit));
__ ldp(t6, t7, Address(__ pre(s, 8 * unit)));
+ int prefetch = PrefetchCopyIntervalInBytes;
+ bool use_stride = false;
+ if (direction == copy_backwards) {
+ use_stride = prefetch > 256;
+ prefetch = -prefetch;
+ if (use_stride) __ mov(stride, prefetch);
+ }
+
__ bind(again);
- if (direction == copy_forwards && PrefetchCopyIntervalInBytes > 0)
- __ prfm(Address(s, PrefetchCopyIntervalInBytes), PLDL1KEEP);
+ if (PrefetchCopyIntervalInBytes > 0)
+ __ prfm(use_stride ? Address(s, stride) : Address(s, prefetch), PLDL1KEEP);
__ stp(t0, t1, Address(d, 2 * unit));
__ ldp(t0, t1, Address(s, 2 * unit));
@@ -1151,8 +1166,11 @@
// caller can pass a 64-bit byte count here (from Unsafe.copyMemory)
BLOCK_COMMENT("Entry:");
}
- __ cmp(d, s);
- __ br(Assembler::LS, nooverlap_target);
+
+ // use fwd copy when (d-s) above_equal (count*size)
+ __ sub(rscratch1, d, s);
+ __ cmp(rscratch1, count, Assembler::LSL, exact_log2(size));
+ __ br(Assembler::HS, nooverlap_target);
if (is_oop) {
__ push(RegSet::of(d, count), sp);
--- a/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/aarch64/vm/vm_version_aarch64.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -120,7 +120,14 @@
FLAG_SET_DEFAULT(AllocatePrefetchStepSize, 64);
FLAG_SET_DEFAULT(PrefetchScanIntervalInBytes, 256);
FLAG_SET_DEFAULT(PrefetchFieldsAhead, 256);
- FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 256);
+ if (FLAG_IS_DEFAULT(PrefetchCopyIntervalInBytes))
+ FLAG_SET_DEFAULT(PrefetchCopyIntervalInBytes, 256);
+ if ((PrefetchCopyIntervalInBytes & 7) || (PrefetchCopyIntervalInBytes >= 32768)) {
+ warning("PrefetchCopyIntervalInBytes must be a multiple of 8 and < 32768");
+ PrefetchCopyIntervalInBytes &= ~7;
+ if (PrefetchCopyIntervalInBytes >= 32768)
+ PrefetchCopyIntervalInBytes = 32760;
+ }
unsigned long auxv = getauxval(AT_HWCAP);
--- a/hotspot/src/cpu/aarch64/vm/vtableStubs_aarch64.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/aarch64/vm/vtableStubs_aarch64.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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.
*
@@ -73,7 +73,7 @@
if (DebugVtables) {
Label L;
// check offset vs vtable length
- __ ldrw(rscratch1, Address(r19, InstanceKlass::vtable_length_offset() * wordSize));
+ __ ldrw(rscratch1, Address(r19, Klass::vtable_length_offset()));
__ cmpw(rscratch1, vtable_index * vtableEntry::size());
__ br(Assembler::GT, L);
__ enter();
--- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1583,13 +1583,13 @@
"caller must use same register for non-constant itable index as for method");
// Compute start of first itableOffsetEntry (which is at the end of the vtable).
- int vtable_base = InstanceKlass::vtable_start_offset() * wordSize;
+ int vtable_base = in_bytes(Klass::vtable_start_offset());
int itentry_off = itableMethodEntry::method_offset_in_bytes();
int logMEsize = exact_log2(itableMethodEntry::size() * wordSize);
int scan_step = itableOffsetEntry::size() * wordSize;
- int log_vte_size= exact_log2(vtableEntry::size() * wordSize);
-
- lwz(scan_temp, InstanceKlass::vtable_length_offset() * wordSize, recv_klass);
+ int log_vte_size= exact_log2(vtableEntry::size_in_bytes());
+
+ lwz(scan_temp, in_bytes(Klass::vtable_length_offset()), recv_klass);
// %%% We should store the aligned, prescaled offset in the klassoop.
// Then the next several instructions would fold away.
@@ -1657,7 +1657,7 @@
assert_different_registers(recv_klass, method_result, vtable_index.register_or_noreg());
- const int base = InstanceKlass::vtable_start_offset() * wordSize;
+ const int base = in_bytes(Klass::vtable_start_offset());
assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
if (vtable_index.is_register()) {
--- a/hotspot/src/cpu/ppc/vm/ppc.ad Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/ppc/vm/ppc.ad Wed Jul 05 21:21:58 2017 +0200
@@ -3568,8 +3568,8 @@
__ load_klass(R11_scratch1, R3);
- int entry_offset = InstanceKlass::vtable_start_offset() + _vtable_index * vtableEntry::size();
- int v_off = entry_offset * wordSize + vtableEntry::method_offset_in_bytes();
+ int entry_offset = in_bytes(Klass::vtable_start_offset()) + _vtable_index * vtableEntry::size_in_bytes();
+ int v_off = entry_offset + vtableEntry::method_offset_in_bytes();
__ li(R19_method, v_off);
__ ldx(R19_method/*method oop*/, R19_method/*method offset*/, R11_scratch1/*class*/);
// NOTE: for vtable dispatches, the vtable entry will never be
--- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2015 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -3282,9 +3282,9 @@
const Register Rtarget_method = Rindex;
// Get target method & entry point.
- const int base = InstanceKlass::vtable_start_offset() * wordSize;
+ const int base = in_bytes(Klass::vtable_start_offset());
// Calc vtable addr scale the vtable index by 8.
- __ sldi(Rindex, Rindex, exact_log2(vtableEntry::size() * wordSize));
+ __ sldi(Rindex, Rindex, exact_log2(vtableEntry::size_in_bytes()));
// Load target.
__ addi(Rrecv_klass, Rrecv_klass, base + vtableEntry::method_offset_in_bytes());
__ ldx(Rtarget_method, Rindex, Rrecv_klass);
--- a/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/ppc/vm/vtableStubs_ppc_64.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -80,14 +80,14 @@
__ load_klass(rcvr_klass, R3);
// Set method (in case of interpreted method), and destination address.
- int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size();
+ int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index*vtableEntry::size_in_bytes();
#ifndef PRODUCT
if (DebugVtables) {
Label L;
// Check offset vs vtable length.
const Register vtable_len = R12_scratch2;
- __ lwz(vtable_len, InstanceKlass::vtable_length_offset()*wordSize, rcvr_klass);
+ __ lwz(vtable_len, in_bytes(Klass::vtable_length_offset()), rcvr_klass);
__ cmpwi(CCR0, vtable_len, vtable_index*vtableEntry::size());
__ bge(CCR0, L);
__ li(R12_scratch2, vtable_index);
@@ -96,7 +96,7 @@
}
#endif
- int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes();
+ int v_off = entry_offset + vtableEntry::method_offset_in_bytes();
__ ld(R19_method, v_off, rcvr_klass);
@@ -163,13 +163,13 @@
__ load_klass(rcvr_klass, R3_ARG1);
BLOCK_COMMENT("Load start of itable entries into itable_entry.");
- __ lwz(vtable_len, InstanceKlass::vtable_length_offset() * wordSize, rcvr_klass);
- __ slwi(vtable_len, vtable_len, exact_log2(vtableEntry::size() * wordSize));
+ __ lwz(vtable_len, in_bytes(Klass::vtable_length_offset()), rcvr_klass);
+ __ slwi(vtable_len, vtable_len, exact_log2(vtableEntry::size_in_bytes()));
__ add(itable_entry_addr, vtable_len, rcvr_klass);
// Loop over all itable entries until desired interfaceOop(Rinterface) found.
BLOCK_COMMENT("Increment itable_entry_addr in loop.");
- const int vtable_base_offset = InstanceKlass::vtable_start_offset() * wordSize;
+ const int vtable_base_offset = in_bytes(Klass::vtable_start_offset());
__ addi(itable_entry_addr, itable_entry_addr, vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes());
const int itable_offset_search_inc = itableOffsetEntry::size() * wordSize;
--- a/hotspot/src/cpu/sparc/vm/copy_sparc.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/sparc/vm/copy_sparc.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -180,6 +180,9 @@
typedef void (*_zero_Fn)(HeapWord* to, size_t count);
+// Only used for heap objects, so align_object_offset.
+// All other platforms pd_fill_to_aligned_words simply calls pd_fill_to_words, don't
+// know why this one is different.
static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) {
assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation");
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -2188,30 +2188,18 @@
}
// Compute start of first itableOffsetEntry (which is at the end of the vtable)
- int vtable_base = InstanceKlass::vtable_start_offset() * wordSize;
+ int vtable_base = in_bytes(Klass::vtable_start_offset());
int scan_step = itableOffsetEntry::size() * wordSize;
- int vte_size = vtableEntry::size() * wordSize;
-
- lduw(recv_klass, InstanceKlass::vtable_length_offset() * wordSize, scan_temp);
+ int vte_size = vtableEntry::size_in_bytes();
+
+ lduw(recv_klass, in_bytes(Klass::vtable_length_offset()), scan_temp);
// %%% We should store the aligned, prescaled offset in the klassoop.
// Then the next several instructions would fold away.
- int round_to_unit = ((HeapWordsPerLong > 1) ? BytesPerLong : 0);
int itb_offset = vtable_base;
- if (round_to_unit != 0) {
- // hoist first instruction of round_to(scan_temp, BytesPerLong):
- itb_offset += round_to_unit - wordSize;
- }
- int itb_scale = exact_log2(vtableEntry::size() * wordSize);
+ int itb_scale = exact_log2(vtableEntry::size_in_bytes());
sll(scan_temp, itb_scale, scan_temp);
add(scan_temp, itb_offset, scan_temp);
- if (round_to_unit != 0) {
- // Round up to align_object_offset boundary
- // see code for InstanceKlass::start_of_itable!
- // Was: round_to(scan_temp, BytesPerLong);
- // Hoisted: add(scan_temp, BytesPerLong-1, scan_temp);
- and3(scan_temp, -round_to_unit, scan_temp);
- }
add(recv_klass, scan_temp, scan_temp);
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
@@ -2280,16 +2268,16 @@
Register method_result) {
assert_different_registers(recv_klass, method_result, vtable_index.register_or_noreg());
Register sethi_temp = method_result;
- const int base = (InstanceKlass::vtable_start_offset() * wordSize +
- // method pointer offset within the vtable entry:
- vtableEntry::method_offset_in_bytes());
+ const int base = in_bytes(Klass::vtable_start_offset()) +
+ // method pointer offset within the vtable entry:
+ vtableEntry::method_offset_in_bytes();
RegisterOrConstant vtable_offset = vtable_index;
// Each of the following three lines potentially generates an instruction.
// But the total number of address formation instructions will always be
// at most two, and will often be zero. In any case, it will be optimal.
// If vtable_index is a register, we will have (sll_ptr N,x; inc_ptr B,x; ld_ptr k,x).
// If vtable_index is a constant, we will have at most (set B+X<<N,t; ld_ptr k,t).
- vtable_offset = regcon_sll_ptr(vtable_index, exact_log2(vtableEntry::size() * wordSize), vtable_offset);
+ vtable_offset = regcon_sll_ptr(vtable_index, exact_log2(vtableEntry::size_in_bytes()), vtable_offset);
vtable_offset = regcon_inc_ptr(vtable_offset, base, vtable_offset, sethi_temp);
Address vtable_entry_addr(recv_klass, ensure_simm13_or_reg(vtable_offset, sethi_temp));
ld_ptr(vtable_entry_addr, method_result);
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
//
-// Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 1998, 2016, 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
@@ -601,8 +601,8 @@
NativeCall::instruction_size); // sethi; setlo; call; delay slot
} else {
assert(!UseInlineCaches, "expect vtable calls only if not using ICs");
- int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size();
- int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes();
+ int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index*vtableEntry::size_in_bytes();
+ int v_off = entry_offset + vtableEntry::method_offset_in_bytes();
int klass_load_size;
if (UseCompressedClassPointers) {
assert(Universe::heap() != NULL, "java heap should be initialized");
@@ -2658,8 +2658,8 @@
} else {
klass_load_size = 1*BytesPerInstWord;
}
- int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size();
- int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes();
+ int entry_offset = in_bytes(Klass::vtable_start_offset()) + vtable_index*vtableEntry::size_in_bytes();
+ int v_off = entry_offset + vtableEntry::method_offset_in_bytes();
if (Assembler::is_simm13(v_off)) {
__ ld_ptr(G3, v_off, G5_method);
} else {
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -3153,14 +3153,11 @@
//
// compute start of first itableOffsetEntry (which is at end of vtable)
- const int base = InstanceKlass::vtable_start_offset() * wordSize;
+ const int base = in_bytes(Klass::vtable_start_offset());
Label search;
Register Rtemp = O1_flags;
- __ ld(O2_Klass, InstanceKlass::vtable_length_offset() * wordSize, Rtemp);
- if (align_object_offset(1) > 1) {
- __ round_to(Rtemp, align_object_offset(1));
- }
+ __ ld(O2_Klass, in_bytes(Klass::vtable_length_offset()), Rtemp);
__ sll(Rtemp, LogBytesPerWord, Rtemp); // Rscratch *= 4;
if (Assembler::is_simm13(base)) {
__ add(Rtemp, base, Rtemp);
--- a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -78,7 +78,7 @@
if (DebugVtables) {
Label L;
// check offset vs vtable length
- __ ld(G3_scratch, InstanceKlass::vtable_length_offset()*wordSize, G5);
+ __ ld(G3_scratch, in_bytes(Klass::vtable_length_offset()), G5);
__ cmp_and_br_short(G5, vtable_index*vtableEntry::size(), Assembler::greaterUnsigned, Assembler::pt, L);
__ set(vtable_index, O2);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), O0, O2);
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -5867,22 +5867,17 @@
"caller must use same register for non-constant itable index as for method");
// Compute start of first itableOffsetEntry (which is at the end of the vtable)
- int vtable_base = InstanceKlass::vtable_start_offset() * wordSize;
+ int vtable_base = in_bytes(Klass::vtable_start_offset());
int itentry_off = itableMethodEntry::method_offset_in_bytes();
int scan_step = itableOffsetEntry::size() * wordSize;
- int vte_size = vtableEntry::size() * wordSize;
+ int vte_size = vtableEntry::size_in_bytes();
Address::ScaleFactor times_vte_scale = Address::times_ptr;
assert(vte_size == wordSize, "else adjust times_vte_scale");
- movl(scan_temp, Address(recv_klass, InstanceKlass::vtable_length_offset() * wordSize));
+ movl(scan_temp, Address(recv_klass, Klass::vtable_length_offset()));
// %%% Could store the aligned, prescaled offset in the klassoop.
lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));
- if (HeapWordsPerLong > 1) {
- // Round up to align_object_offset boundary
- // see code for InstanceKlass::start_of_itable!
- round_to(scan_temp, BytesPerLong);
- }
// Adjust recv_klass by scaled itable_index, so we can free itable_index.
assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
@@ -5930,7 +5925,7 @@
void MacroAssembler::lookup_virtual_method(Register recv_klass,
RegisterOrConstant vtable_index,
Register method_result) {
- const int base = InstanceKlass::vtable_start_offset() * wordSize;
+ const int base = in_bytes(Klass::vtable_start_offset());
assert(vtableEntry::size() * wordSize == wordSize, "else adjust the scaling in the code below");
Address vtable_entry_addr(recv_klass,
vtable_index, Address::times_ptr,
--- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -85,7 +85,7 @@
if (DebugVtables) {
Label L;
// check offset vs vtable length
- __ cmpl(Address(rax, InstanceKlass::vtable_length_offset()*wordSize), vtable_index*vtableEntry::size());
+ __ cmpl(Address(rax, Klass::vtable_length_offset()), vtable_index*vtableEntry::size());
__ jcc(Assembler::greater, L);
__ movl(rbx, vtable_index);
__ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), rcx, rbx);
--- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -77,7 +77,7 @@
if (DebugVtables) {
Label L;
// check offset vs vtable length
- __ cmpl(Address(rax, InstanceKlass::vtable_length_offset() * wordSize),
+ __ cmpl(Address(rax, Klass::vtable_length_offset()),
vtable_index * vtableEntry::size());
__ jcc(Assembler::greater, L);
__ movl(rbx, vtable_index);
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java Wed Jul 05 21:21:58 2017 +0200
@@ -141,15 +141,19 @@
return;
}
+ // Create frame first, to catch any GUI creation issues
+ // before we initialize agent
+
+ frame = new JFrame("HSDB - HotSpot Debugger");
+ frame.setSize(800, 600);
+ frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ frame.addWindowListener(new CloseUI());
+
agent = new HotSpotAgent();
workerThread = new WorkerThread();
attachMenuItems = new java.util.ArrayList();
detachMenuItems = new java.util.ArrayList();
- frame = new JFrame("HSDB - HotSpot Debugger");
- frame.setSize(800, 600);
- frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
- frame.addWindowListener(new CloseUI());
JMenuBar menuBar = new JMenuBar();
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ArrayKlass.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -48,7 +48,6 @@
dimension = new CIntField(type.getCIntegerField("_dimension"), 0);
higherDimension = new MetadataField(type.getAddressField("_higher_dimension"), 0);
lowerDimension = new MetadataField(type.getAddressField("_lower_dimension"), 0);
- vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), 0);
javaLangCloneableName = null;
javaLangObjectName = null;
javaIoSerializableName = null;
@@ -61,7 +60,6 @@
private static CIntField dimension;
private static MetadataField higherDimension;
private static MetadataField lowerDimension;
- private static CIntField vtableLen;
public Klass getJavaSuper() {
SystemDictionary sysDict = VM.getVM().getSystemDictionary();
@@ -71,7 +69,6 @@
public long getDimension() { return dimension.getValue(this); }
public Klass getHigherDimension() { return (Klass) higherDimension.getValue(this); }
public Klass getLowerDimension() { return (Klass) lowerDimension.getValue(this); }
- public long getVtableLen() { return vtableLen.getValue(this); }
// constant class names - javaLangCloneable, javaIoSerializable, javaLangObject
// Initialized lazily to avoid initialization ordering dependencies between ArrayKlass and SymbolTable
@@ -140,6 +137,5 @@
visitor.doCInt(dimension, true);
visitor.doMetadata(higherDimension, true);
visitor.doMetadata(lowerDimension, true);
- visitor.doCInt(vtableLen, true);
}
}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -696,7 +696,7 @@
}
public long getSize() {
- return Oop.alignObjectSize(headerSize + getLength());
+ return alignSize(headerSize + getLength());
}
//----------------------------------------------------------------------
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -70,7 +70,7 @@
public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); }
public long getSize() {
- return Oop.alignObjectSize(baseOffset + getLength() * elementSize);
+ return alignSize(baseOffset + getLength() * elementSize);
}
public ConstantPoolCacheEntry getEntryAt(int i) {
@@ -79,8 +79,7 @@
}
public int getIntAt(int entry, int fld) {
- //alignObjectSize ?
- long offset = baseOffset + /*alignObjectSize*/entry * elementSize + fld * intSize;
+ long offset = baseOffset + entry * elementSize + fld * intSize;
return (int) getAddress().getCIntegerAt(offset, intSize, true );
}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -84,13 +84,12 @@
nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), 0);
isMarkedDependent = new CIntField(type.getCIntegerField("_is_marked_dependent"), 0);
initState = new CIntField(type.getCIntegerField("_init_state"), 0);
- vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), 0);
itableLen = new CIntField(type.getCIntegerField("_itable_len"), 0);
breakpoints = type.getAddressField("_breakpoints");
genericSignatureIndex = new CIntField(type.getCIntegerField("_generic_signature_index"), 0);
majorVersion = new CIntField(type.getCIntegerField("_major_version"), 0);
minorVersion = new CIntField(type.getCIntegerField("_minor_version"), 0);
- headerSize = Oop.alignObjectOffset(type.getSize());
+ headerSize = type.getSize();
// read field offset constants
ACCESS_FLAGS_OFFSET = db.lookupIntConstant("FieldInfo::access_flags_offset").intValue();
@@ -143,7 +142,6 @@
private static CIntField nonstaticOopMapSize;
private static CIntField isMarkedDependent;
private static CIntField initState;
- private static CIntField vtableLen;
private static CIntField itableLen;
private static AddressField breakpoints;
private static CIntField genericSignatureIndex;
@@ -242,8 +240,7 @@
}
public long getSize() {
- return Oop.alignObjectSize(getHeaderSize() + Oop.alignObjectOffset(getVtableLen()) +
- Oop.alignObjectOffset(getItableLen()) + Oop.alignObjectOffset(getNonstaticOopMapSize()));
+ return alignSize(getHeaderSize() + getVtableLen() + getItableLen() + getNonstaticOopMapSize());
}
public static long getHeaderSize() { return headerSize; }
@@ -352,7 +349,6 @@
public long getStaticOopFieldCount() { return staticOopFieldCount.getValue(this); }
public long getNonstaticOopMapSize() { return nonstaticOopMapSize.getValue(this); }
public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; }
- public long getVtableLen() { return vtableLen.getValue(this); }
public long getItableLen() { return itableLen.getValue(this); }
public long majorVersion() { return majorVersion.getValue(this); }
public long minorVersion() { return minorVersion.getValue(this); }
@@ -548,7 +544,6 @@
visitor.doCInt(nonstaticOopMapSize, true);
visitor.doCInt(isMarkedDependent, true);
visitor.doCInt(initState, true);
- visitor.doCInt(vtableLen, true);
visitor.doCInt(itableLen, true);
}
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -61,6 +61,7 @@
}
subklass = new MetadataField(type.getAddressField("_subklass"), 0);
nextSibling = new MetadataField(type.getAddressField("_next_sibling"), 0);
+ vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), 0);
LH_INSTANCE_SLOW_PATH_BIT = db.lookupIntConstant("Klass::_lh_instance_slow_path_bit").intValue();
LH_LOG2_ELEMENT_SIZE_SHIFT = db.lookupIntConstant("Klass::_lh_log2_element_size_shift").intValue();
@@ -71,6 +72,7 @@
LH_ARRAY_TAG_OBJ_VALUE = db.lookupIntConstant("Klass::_lh_array_tag_obj_value").intValue();
}
+
public Klass(Address addr) {
super(addr);
}
@@ -91,6 +93,7 @@
private static MetadataField subklass;
private static MetadataField nextSibling;
private static sun.jvm.hotspot.types.Field traceIDField;
+ private static CIntField vtableLen;
private Address getValue(AddressField field) {
return addr.getAddressAt(field.getOffset());
@@ -111,6 +114,7 @@
public AccessFlags getAccessFlagsObj(){ return new AccessFlags(getAccessFlags()); }
public Klass getSubklassKlass() { return (Klass) subklass.getValue(this); }
public Klass getNextSiblingKlass() { return (Klass) nextSibling.getValue(this); }
+ public long getVtableLen() { return vtableLen.getValue(this); }
public long traceID() {
if (traceIDField == null) return 0;
@@ -179,6 +183,7 @@
visitor.doCInt(accessFlags, true);
visitor.doMetadata(subklass, true);
visitor.doMetadata(nextSibling, true);
+ visitor.doCInt(vtableLen, true);
}
public long getObjectSize() {
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Metadata.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -44,6 +44,11 @@
super(addr);
}
+ public static long alignSize(long size) {
+ // natural word size.
+ return VM.getVM().alignUp(size, VM.getVM().getBytesPerWord());
+ }
+
private static VirtualBaseConstructor<Metadata> metadataConstructor;
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/MethodData.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -252,7 +252,7 @@
}
int size() {
- return (int)Oop.alignObjectSize(VM.getVM().alignUp(sizeInBytes(), VM.getVM().getBytesPerWord())/VM.getVM().getBytesPerWord());
+ return (int)alignSize(VM.getVM().alignUp(sizeInBytes(), VM.getVM().getBytesPerWord())/VM.getVM().getBytesPerWord());
}
ParametersTypeData<Klass,Method> parametersTypeData() {
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/WorkerThread.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/WorkerThread.java Wed Jul 05 21:21:58 2017 +0200
@@ -35,7 +35,11 @@
public WorkerThread() {
mqb = new MessageQueueBackend();
mq = mqb.getFirstQueue();
- new Thread(new MainLoop()).start();
+
+ // Enable to terminate this worker during runnning by daemonize.
+ Thread mqthread = new Thread(new MainLoop());
+ mqthread.setDaemon(true);
+ mqthread.start();
}
/** Runs the given Runnable in the thread represented by this
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java Wed Jul 05 21:21:58 2017 +0200
@@ -76,14 +76,14 @@
public static final Register zr = r31;
public static final Register sp = r31;
+ // @formatter:off
public static final Register[] cpuRegisters = {
- // @formatter:off
r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15,
r16, r17, r18, r19, r20, r21, r22, r23,
r24, r25, r26, r27, r28, r29, r30, r31
- // @formatter:on
};
+ // @formatter:on
public static final RegisterCategory SIMD = new RegisterCategory("SIMD");
@@ -121,17 +121,17 @@
public static final Register v30 = new Register(62, 30, "v30", SIMD);
public static final Register v31 = new Register(63, 31, "v31", SIMD);
+ // @formatter:off
public static final Register[] simdRegisters = {
- // @formatter:off
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10, v11, v12, v13, v14, v15,
v16, v17, v18, v19, v20, v21, v22, v23,
v24, v25, v26, v27, v28, v29, v30, v31
- // @formatter:on
};
+ // @formatter:on
+ // @formatter:off
public static final Register[] allRegisters = {
- // @formatter:off
r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15,
r16, r17, r18, r19, r20, r21, r22, r23,
@@ -141,14 +141,14 @@
v8, v9, v10, v11, v12, v13, v14, v15,
v16, v17, v18, v19, v20, v21, v22, v23,
v24, v25, v26, v27, v28, v29, v30, v31
- // @formatter:on
};
+ // @formatter:on
/**
* Basic set of CPU features mirroring what is returned from the cpuid instruction. See:
* {@code VM_Version::cpuFeatureFlags}.
*/
- public static enum CPUFeature {
+ public enum CPUFeature {
FP,
ASIMD,
EVTSTRM,
@@ -166,7 +166,7 @@
/**
* Set of flags to control code emission.
*/
- public static enum Flag {
+ public enum Flag {
UseBarriersForVolatile,
UseCRC32,
UseNeon
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64Kind.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64Kind.java Wed Jul 05 21:21:58 2017 +0200
@@ -58,13 +58,13 @@
private final AArch64Kind scalar;
private final EnumKey<AArch64Kind> key = new EnumKey<>(this);
- private AArch64Kind(int size) {
+ AArch64Kind(int size) {
this.size = size;
this.scalar = this;
this.vectorLength = 1;
}
- private AArch64Kind(int size, AArch64Kind scalar) {
+ AArch64Kind(int size, AArch64Kind scalar) {
this.size = size;
this.scalar = scalar;
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java Wed Jul 05 21:21:58 2017 +0200
@@ -169,7 +169,7 @@
* Basic set of CPU features mirroring what is returned from the cpuid instruction. See:
* {@code VM_Version::cpuFeatureFlags}.
*/
- public static enum CPUFeature {
+ public enum CPUFeature {
CX8,
CMOV,
FXSR,
@@ -210,7 +210,7 @@
/**
* Set of flags to control code emission.
*/
- public static enum Flag {
+ public enum Flag {
UseCountLeadingZerosInstruction,
UseCountTrailingZerosInstruction
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64Kind.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64Kind.java Wed Jul 05 21:21:58 2017 +0200
@@ -74,13 +74,13 @@
private final AMD64Kind scalar;
private final EnumKey<AMD64Kind> key = new EnumKey<>(this);
- private AMD64Kind(int size) {
+ AMD64Kind(int size) {
this.size = size;
this.scalar = this;
this.vectorLength = 1;
}
- private AMD64Kind(int size, AMD64Kind scalar) {
+ AMD64Kind(int size, AMD64Kind scalar) {
this.size = size;
this.scalar = scalar;
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/SourceStackTrace.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/SourceStackTrace.java Wed Jul 05 21:21:58 2017 +0200
@@ -23,7 +23,7 @@
package jdk.vm.ci.code;
/**
- * Class representing a exception with a stack trace of the currently processed position in the
+ * Class representing an exception with a stack trace of the currently processed position in the
* compiled Java program instead of the stack trace of the compiler. The exception of the compiler
* is saved as the cause of this exception.
*/
@@ -36,7 +36,7 @@
private static final long serialVersionUID = 6279381376051787907L;
@Override
- public final synchronized Throwable fillInStackTrace() {
+ public synchronized Throwable fillInStackTrace() {
assert elements != null;
setStackTrace(elements);
return this;
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java Wed Jul 05 21:21:58 2017 +0200
@@ -49,7 +49,7 @@
public static final Type[] VALUES = values();
- private HotSpotCallingConventionType(boolean out) {
+ HotSpotCallingConventionType(boolean out) {
this.out = out;
}
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java Wed Jul 05 21:21:58 2017 +0200
@@ -24,6 +24,7 @@
import jdk.vm.ci.code.BytecodeFrame;
import jdk.vm.ci.code.CompiledCode;
+import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.DataPatch;
import jdk.vm.ci.code.site.Infopoint;
import jdk.vm.ci.code.site.Site;
@@ -99,9 +100,9 @@
protected final int totalFrameSize;
/**
- * Offset in bytes for the custom stack area (relative to sp).
+ * The deopt rescue slot. Must be non-null if there is a safepoint in the method.
*/
- protected final int customStackAreaOffset;
+ protected final StackSlot deoptRescueSlot;
public static class Comment {
@@ -115,7 +116,7 @@
}
public HotSpotCompiledCode(String name, byte[] targetCode, int targetCodeSize, Site[] sites, Assumption[] assumptions, ResolvedJavaMethod[] methods, Comment[] comments, byte[] dataSection,
- int dataSectionAlignment, DataPatch[] dataSectionPatches, boolean isImmutablePIC, int totalFrameSize, int customStackAreaOffset) {
+ int dataSectionAlignment, DataPatch[] dataSectionPatches, boolean isImmutablePIC, int totalFrameSize, StackSlot deoptRescueSlot) {
this.name = name;
this.targetCode = targetCode;
this.targetCodeSize = targetCodeSize;
@@ -129,7 +130,7 @@
this.dataSectionPatches = dataSectionPatches;
this.isImmutablePIC = isImmutablePIC;
this.totalFrameSize = totalFrameSize;
- this.customStackAreaOffset = customStackAreaOffset;
+ this.deoptRescueSlot = deoptRescueSlot;
assert validateFrames();
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java Wed Jul 05 21:21:58 2017 +0200
@@ -22,6 +22,7 @@
*/
package jdk.vm.ci.hotspot;
+import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.DataPatch;
import jdk.vm.ci.code.site.Site;
import jdk.vm.ci.inittimer.SuppressFBWarnings;
@@ -55,9 +56,9 @@
@SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "set by the VM") private String installationFailureMessage;
public HotSpotCompiledNmethod(String name, byte[] targetCode, int targetCodeSize, Site[] sites, Assumption[] assumptions, ResolvedJavaMethod[] methods, Comment[] comments, byte[] dataSection,
- int dataSectionAlignment, DataPatch[] dataSectionPatches, boolean isImmutablePIC, int totalFrameSize, int customStackAreaOffset, HotSpotResolvedJavaMethod method, int entryBCI,
+ int dataSectionAlignment, DataPatch[] dataSectionPatches, boolean isImmutablePIC, int totalFrameSize, StackSlot deoptRescueSlot, HotSpotResolvedJavaMethod method, int entryBCI,
int id, long jvmciEnv, boolean hasUnsafeAccess) {
- super(name, targetCode, targetCodeSize, sites, assumptions, methods, comments, dataSection, dataSectionAlignment, dataSectionPatches, isImmutablePIC, totalFrameSize, customStackAreaOffset);
+ super(name, targetCode, targetCodeSize, sites, assumptions, methods, comments, dataSection, dataSectionAlignment, dataSectionPatches, isImmutablePIC, totalFrameSize, deoptRescueSlot);
this.method = method;
this.entryBCI = entryBCI;
this.id = id;
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java Wed Jul 05 21:21:58 2017 +0200
@@ -126,7 +126,7 @@
private static final int InternalMin = config().jvmConstantInternalMin;
private static final int InternalMax = config().jvmConstantInternalMax;
- private JVM_CONSTANT(int tag) {
+ JVM_CONSTANT(int tag) {
this.tag = tag;
}
@@ -171,7 +171,7 @@
int lastCpi = Integer.MIN_VALUE;
JavaType javaType;
- public LookupTypeCacheElement(int lastCpi, JavaType javaType) {
+ LookupTypeCacheElement(int lastCpi, JavaType javaType) {
super();
this.lastCpi = lastCpi;
this.javaType = javaType;
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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,7 +22,9 @@
*/
package jdk.vm.ci.hotspot;
-public class HotSpotForeignCallTarget {
+import jdk.vm.ci.meta.InvokeTarget;
+
+public class HotSpotForeignCallTarget implements InvokeTarget {
/**
* The entry point address of this call's target.
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Wed Jul 05 21:21:58 2017 +0200
@@ -43,6 +43,7 @@
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.common.JVMCIError;
import jdk.vm.ci.inittimer.InitTimer;
+import jdk.vm.ci.inittimer.SuppressFBWarnings;
import jdk.vm.ci.meta.JVMCIMetaAccessContext;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
@@ -115,7 +116,7 @@
private boolean isDefault;
private final String help;
- private Option(Class<?> type, Object defaultValue, String help) {
+ Option(Class<?> type, Object defaultValue, String help) {
assert Character.isUpperCase(name().charAt(0)) : "Option name must start with upper-case letter: " + name();
this.type = type;
this.value = UNINITIALIZED;
@@ -123,6 +124,7 @@
this.help = help;
}
+ @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum")
private Object getValue() {
if (value == UNINITIALIZED) {
String propertyValue = VM.getSavedProperty(JVMCI_OPTION_PROPERTY_PREFIX + name());
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java Wed Jul 05 21:21:58 2017 +0200
@@ -38,7 +38,7 @@
protected final HotSpotJVMCIRuntimeProvider runtime;
- public HotSpotMemoryAccessProviderImpl(HotSpotJVMCIRuntimeProvider runtime) {
+ HotSpotMemoryAccessProviderImpl(HotSpotJVMCIRuntimeProvider runtime) {
this.runtime = runtime;
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java Wed Jul 05 21:21:58 2017 +0200
@@ -413,7 +413,7 @@
private static final int COUNTER_DATA_SIZE = cellIndexToOffset(1);
private static final int COUNTER_DATA_COUNT_OFFSET = cellIndexToOffset(config.methodDataCountOffset);
- public CounterData() {
+ CounterData() {
super(Tag.CounterData, COUNTER_DATA_SIZE);
}
@@ -442,7 +442,7 @@
protected static final int TAKEN_COUNT_OFFSET = cellIndexToOffset(config.jumpDataTakenOffset);
protected static final int TAKEN_DISPLACEMENT_OFFSET = cellIndexToOffset(config.jumpDataDisplacementOffset);
- public JumpData() {
+ JumpData() {
super(Tag.JumpData, JUMP_DATA_SIZE);
}
@@ -476,7 +476,7 @@
final long[] counts;
final long totalCount;
- public RawItemProfile(int entries, T[] items, long[] counts, long totalCount) {
+ RawItemProfile(int entries, T[] items, long[] counts, long totalCount) {
this.entries = entries;
this.items = items;
this.counts = counts;
@@ -587,7 +587,7 @@
private static final int TYPE_CHECK_DATA_SIZE = cellIndexToOffset(2) + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
- public ReceiverTypeData() {
+ ReceiverTypeData() {
super(Tag.ReceiverTypeData, TYPE_CHECK_DATA_SIZE);
}
@@ -612,7 +612,7 @@
private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_OFFSET = TYPE_DATA_FIRST_TYPE_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
private static final int VIRTUAL_CALL_DATA_FIRST_METHOD_COUNT_OFFSET = TYPE_DATA_FIRST_TYPE_COUNT_OFFSET + TYPE_DATA_ROW_SIZE * config.typeProfileWidth;
- public VirtualCallData() {
+ VirtualCallData() {
super(Tag.VirtualCallData, VIRTUAL_CALL_DATA_SIZE);
}
@@ -714,7 +714,7 @@
private static class VirtualCallTypeData extends VirtualCallData {
- public VirtualCallTypeData() {
+ VirtualCallTypeData() {
super(Tag.VirtualCallTypeData, 0);
}
@@ -730,7 +730,7 @@
private static final int RET_DATA_ROW_SIZE = cellsToBytes(3);
private static final int RET_DATA_SIZE = cellIndexToOffset(1) + RET_DATA_ROW_SIZE * config.bciProfileWidth;
- public RetData() {
+ RetData() {
super(Tag.RetData, RET_DATA_SIZE);
}
}
@@ -740,7 +740,7 @@
private static final int BRANCH_DATA_SIZE = cellIndexToOffset(3);
private static final int NOT_TAKEN_COUNT_OFFSET = cellIndexToOffset(config.branchDataNotTakenOffset);
- public BranchData() {
+ BranchData() {
super(Tag.BranchData, BRANCH_DATA_SIZE);
}
@@ -773,7 +773,7 @@
private static final int ARRAY_DATA_LENGTH_OFFSET = cellIndexToOffset(config.arrayDataArrayLenOffset);
protected static final int ARRAY_DATA_START_OFFSET = cellIndexToOffset(config.arrayDataArrayStartOffset);
- public ArrayData(Tag tag, int staticSize) {
+ ArrayData(Tag tag, int staticSize) {
super(tag, staticSize);
}
@@ -800,7 +800,7 @@
private static final int MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(0);
private static final int MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET = ARRAY_DATA_START_OFFSET + cellsToBytes(1);
- public MultiBranchData() {
+ MultiBranchData() {
super(Tag.MultiBranchData, MULTI_BRANCH_DATA_SIZE);
}
@@ -882,13 +882,13 @@
private static final int ARG_INFO_DATA_SIZE = cellIndexToOffset(1);
- public ArgInfoData() {
+ ArgInfoData() {
super(Tag.ArgInfoData, ARG_INFO_DATA_SIZE);
}
}
private static class UnknownProfileData extends AbstractMethodData {
- public UnknownProfileData(Tag tag) {
+ UnknownProfileData(Tag tag) {
super(tag, 0);
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java Wed Jul 05 21:21:58 2017 +0200
@@ -56,7 +56,7 @@
private final int value;
- private Tag(int value) {
+ Tag(int value) {
this.value = value;
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodUnresolved.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodUnresolved.java Wed Jul 05 21:21:58 2017 +0200
@@ -34,7 +34,7 @@
private final Signature signature;
protected JavaType holder;
- public HotSpotMethodUnresolved(String name, Signature signature, JavaType holder) {
+ HotSpotMethodUnresolved(String name, Signature signature, JavaType holder) {
super(name);
this.holder = holder;
this.signature = signature;
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java Wed Jul 05 21:21:58 2017 +0200
@@ -56,7 +56,7 @@
public static class FieldLocationIdentity extends LocationIdentity {
HotSpotResolvedJavaField inner;
- public FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) {
+ FieldLocationIdentity(HotSpotResolvedJavaFieldImpl inner) {
this.inner = inner;
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -597,7 +597,7 @@
}
HotSpotVMConfig config = config();
final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved);
- return config.instanceKlassVtableStartOffset() + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset;
+ return config.klassVtableStartOffset + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset;
}
@Override
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -33,7 +33,6 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.net.URL;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
@@ -49,7 +48,6 @@
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.MetaUtil;
import jdk.vm.ci.meta.ModifiersProvider;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -472,8 +470,8 @@
/* Everything has the core vtable of java.lang.Object */
return config.baseVtableLength();
}
- int result = UNSAFE.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) / (config.vtableEntrySize / config.heapWordSize);
- assert result >= config.baseVtableLength() : UNSAFE.getInt(getMetaspaceKlass() + config.instanceKlassVtableLengthOffset) + " " + config.vtableEntrySize;
+ int result = UNSAFE.getInt(getMetaspaceKlass() + config.klassVtableLengthOffset) / (config.vtableEntrySize / config.heapWordSize);
+ assert result >= config.baseVtableLength() : UNSAFE.getInt(getMetaspaceKlass() + config.klassVtableLengthOffset) + " " + config.vtableEntrySize;
return result;
}
@@ -555,7 +553,7 @@
*
* @param index index to the fields array
*/
- public FieldInfo(int index) {
+ FieldInfo(int index) {
HotSpotVMConfig config = config();
// Get Klass::_fields
final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset);
@@ -839,12 +837,6 @@
}
@Override
- public URL getClassFilePath() {
- Class<?> cls = mirror();
- return cls.getResource(MetaUtil.getSimpleName(cls, true).replace('.', '$') + ".class");
- }
-
- @Override
public boolean isLocal() {
return mirror().isLocalClass();
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java Wed Jul 05 21:21:58 2017 +0200
@@ -27,7 +27,6 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
-import java.net.URL;
import jdk.vm.ci.common.JVMCIError;
import jdk.vm.ci.meta.Assumptions.AssumptionResult;
@@ -240,11 +239,6 @@
}
@Override
- public URL getClassFilePath() {
- return null;
- }
-
- @Override
public boolean isLocal() {
return false;
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -360,7 +360,7 @@
private final long address;
- public VMFields(long address) {
+ VMFields(long address) {
this.address = address;
}
@@ -477,7 +477,7 @@
private final long address;
- public VMTypes(long address) {
+ VMTypes(long address) {
this.address = address;
}
@@ -580,7 +580,7 @@
private final long address;
- public VMIntConstants(long address) {
+ VMIntConstants(long address) {
this.address = address;
}
@@ -639,7 +639,7 @@
private final long address;
- public VMLongConstants(long address) {
+ VMLongConstants(long address) {
this.address = address;
}
@@ -698,7 +698,7 @@
private final long address;
- public VMAddresses(long address) {
+ VMAddresses(long address) {
this.address = address;
}
@@ -753,7 +753,7 @@
private final long nameOffset;
private final long addrOffset;
- public Flags(HashMap<String, VMFields.Field> vmStructs, HashMap<String, VMTypes.Type> vmTypes) {
+ Flags(HashMap<String, VMFields.Field> vmStructs, HashMap<String, VMTypes.Type> vmTypes) {
address = vmStructs.get("Flag::flags").getValue();
entrySize = vmTypes.get("Flag").getSize();
typeOffset = vmStructs.get("Flag::_type").getOffset();
@@ -1031,19 +1031,12 @@
@HotSpotVMField(name = "InstanceKlass::_init_state", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassInitStateOffset;
@HotSpotVMField(name = "InstanceKlass::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassConstantsOffset;
@HotSpotVMField(name = "InstanceKlass::_fields", type = "Array<u2>*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassFieldsOffset;
- @HotSpotVMField(name = "CompilerToVM::Data::InstanceKlass_vtable_start_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int instanceKlassVtableStartOffset;
- @HotSpotVMField(name = "CompilerToVM::Data::InstanceKlass_vtable_length_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int instanceKlassVtableLengthOffset;
+ @HotSpotVMField(name = "CompilerToVM::Data::Klass_vtable_start_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int klassVtableStartOffset;
+ @HotSpotVMField(name = "CompilerToVM::Data::Klass_vtable_length_offset", type = "int", get = HotSpotVMField.Type.VALUE) @Stable public int klassVtableLengthOffset;
@HotSpotVMConstant(name = "InstanceKlass::linked") @Stable public int instanceKlassStateLinked;
@HotSpotVMConstant(name = "InstanceKlass::fully_initialized") @Stable public int instanceKlassStateFullyInitialized;
- /**
- * See {@code InstanceKlass::vtable_start_offset()}.
- */
- public final int instanceKlassVtableStartOffset() {
- return instanceKlassVtableStartOffset * heapWordSize;
- }
-
@HotSpotVMType(name = "arrayOopDesc", get = HotSpotVMType.Type.SIZE) @Stable public int arrayOopDescSize;
/**
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationAction.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationAction.java Wed Jul 05 21:21:58 2017 +0200
@@ -59,7 +59,7 @@
private final boolean invalidatesCompilation;
- private DeoptimizationAction(boolean invalidatesCompilation) {
+ DeoptimizationAction(boolean invalidatesCompilation) {
this.invalidatesCompilation = invalidatesCompilation;
}
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java Wed Jul 05 21:21:58 2017 +0200
@@ -72,7 +72,7 @@
private final Class<?> boxedJavaClass;
private final int slotCount;
- private JavaKind(char typeChar, String javaName, int slotCount, boolean isStackInt, Class<?> primitiveJavaClass, Class<?> boxedJavaClass) {
+ JavaKind(char typeChar, String javaName, int slotCount, boolean isStackInt, Class<?> primitiveJavaClass, Class<?> boxedJavaClass) {
this.typeChar = typeChar;
this.javaName = javaName;
this.slotCount = slotCount;
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LIRKind.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LIRKind.java Wed Jul 05 21:21:58 2017 +0200
@@ -57,7 +57,7 @@
*/
public final class LIRKind {
- private static enum IllegalKind implements PlatformKind {
+ private enum IllegalKind implements PlatformKind {
ILLEGAL;
private final EnumKey<IllegalKind> key = new EnumKey<>(this);
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java Wed Jul 05 21:21:58 2017 +0200
@@ -35,7 +35,7 @@
* Identification for methods defined on the class {@link MethodHandle} that are processed by
* the {@link MethodHandleAccessProvider}.
*/
- public enum IntrinsicMethod {
+ enum IntrinsicMethod {
/** The method {@code MethodHandle.invokeBasic}. */
INVOKE_BASIC,
/** The method {@code MethodHandle.linkToStatic}. */
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PlatformKind.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PlatformKind.java Wed Jul 05 21:21:58 2017 +0200
@@ -33,7 +33,7 @@
}
- public class EnumKey<E extends Enum<E>> implements Key {
+ class EnumKey<E extends Enum<E>> implements Key {
private final Enum<E> e;
public EnumKey(Enum<E> e) {
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java Wed Jul 05 21:21:58 2017 +0200
@@ -23,7 +23,6 @@
package jdk.vm.ci.meta;
import java.lang.annotation.Annotation;
-import java.net.URL;
import jdk.vm.ci.meta.Assumptions.AssumptionResult;
@@ -308,11 +307,6 @@
String getSourceFileName();
/**
- * Returns the class file path - if available - of this type, or {@code null}.
- */
- URL getClassFilePath();
-
- /**
* Returns {@code true} if the type is a local type.
*/
boolean isLocal();
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARCKind.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.sparc/src/jdk/vm/ci/sparc/SPARCKind.java Wed Jul 05 21:21:58 2017 +0200
@@ -47,13 +47,13 @@
private final SPARCKind scalar;
private final EnumKey<SPARCKind> key = new EnumKey<>(this);
- private SPARCKind(int size) {
+ SPARCKind(int size) {
this.size = size;
this.scalar = this;
this.vectorLength = 1;
}
- private SPARCKind(int size, SPARCKind scalar) {
+ SPARCKind(int size, SPARCKind scalar) {
this.size = size;
this.scalar = scalar;
--- a/hotspot/src/os/linux/vm/globals_linux.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/os/linux/vm/globals_linux.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -48,7 +48,10 @@
"Load DLLs with executable-stack attribute in the VM Thread") \
\
product(bool, UseSHM, false, \
- "Use SYSV shared memory for large pages")
+ "Use SYSV shared memory for large pages") \
+ \
+ diagnostic(bool, UseCpuAllocPath, false, \
+ "Use CPU_ALLOC code path in os::active_processor_count ")
//
// Defines Linux-specific default values. The flags are available on all
--- a/hotspot/src/os/linux/vm/os_linux.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
#include "compiler/disassembler.hpp"
#include "interpreter/interpreter.hpp"
#include "jvm_linux.h"
+#include "logging/log.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/filemap.hpp"
#include "mutex_linux.inline.hpp"
@@ -106,6 +107,14 @@
# include <inttypes.h>
# include <sys/ioctl.h>
+#ifndef _GNU_SOURCE
+ #define _GNU_SOURCE
+ #include <sched.h>
+ #undef _GNU_SOURCE
+#else
+ #include <sched.h>
+#endif
+
// if RUSAGE_THREAD for getrusage() has not been defined, do it here. The code calling
// getrusage() is prepared to handle the associated failure.
#ifndef RUSAGE_THREAD
@@ -4762,12 +4771,72 @@
}
}
+// Get the current number of available processors for this process.
+// This value can change at any time during a process's lifetime.
+// sched_getaffinity gives an accurate answer as it accounts for cpusets.
+// If it appears there may be more than 1024 processors then we do a
+// dynamic check - see 6515172 for details.
+// If anything goes wrong we fallback to returning the number of online
+// processors - which can be greater than the number available to the process.
int os::active_processor_count() {
- // Linux doesn't yet have a (official) notion of processor sets,
- // so just return the number of online processors.
- int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);
- assert(online_cpus > 0 && online_cpus <= processor_count(), "sanity check");
- return online_cpus;
+ cpu_set_t cpus; // can represent at most 1024 (CPU_SETSIZE) processors
+ cpu_set_t* cpus_p = &cpus;
+ int cpus_size = sizeof(cpu_set_t);
+
+ int configured_cpus = processor_count(); // upper bound on available cpus
+ int cpu_count = 0;
+
+ // To enable easy testing of the dynamic path on different platforms we
+ // introduce a diagnostic flag: UseCpuAllocPath
+ if (configured_cpus >= CPU_SETSIZE || UseCpuAllocPath) {
+ // kernel may use a mask bigger than cpu_set_t
+ log_trace(os)("active_processor_count: using dynamic path %s"
+ "- configured processors: %d",
+ UseCpuAllocPath ? "(forced) " : "",
+ configured_cpus);
+ cpus_p = CPU_ALLOC(configured_cpus);
+ if (cpus_p != NULL) {
+ cpus_size = CPU_ALLOC_SIZE(configured_cpus);
+ // zero it just to be safe
+ CPU_ZERO_S(cpus_size, cpus_p);
+ }
+ else {
+ // failed to allocate so fallback to online cpus
+ int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);
+ log_trace(os)("active_processor_count: "
+ "CPU_ALLOC failed (%s) - using "
+ "online processor count: %d",
+ strerror(errno), online_cpus);
+ return online_cpus;
+ }
+ }
+ else {
+ log_trace(os)("active_processor_count: using static path - configured processors: %d",
+ configured_cpus);
+ }
+
+ // pid 0 means the current thread - which we have to assume represents the process
+ if (sched_getaffinity(0, cpus_size, cpus_p) == 0) {
+ if (cpus_p != &cpus) {
+ cpu_count = CPU_COUNT_S(cpus_size, cpus_p);
+ }
+ else {
+ cpu_count = CPU_COUNT(cpus_p);
+ }
+ log_trace(os)("active_processor_count: sched_getaffinity processor count: %d", cpu_count);
+ }
+ else {
+ cpu_count = ::sysconf(_SC_NPROCESSORS_ONLN);
+ warning("sched_getaffinity failed (%s)- using online processor count (%d) "
+ "which may exceed available processors", strerror(errno), cpu_count);
+ }
+
+ if (cpus_p != &cpus) {
+ CPU_FREE(cpus_p);
+ }
+
+ assert(cpu_count > 0 && cpu_count <= processor_count(), "sanity check");
+ return cpu_count;
}
void os::set_native_thread_name(const char *name) {
--- a/hotspot/src/os/windows/vm/os_windows.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -5267,8 +5267,29 @@
bool os::find(address addr, outputStream* st) {
- // Nothing yet
- return false;
+ int offset = -1;
+ bool result = false;
+ char buf[256];
+ if (os::dll_address_to_library_name(addr, buf, sizeof(buf), &offset)) {
+ st->print(PTR_FORMAT " ", addr);
+ if (strlen(buf) < sizeof(buf) - 1) {
+ char* p = strrchr(buf, '\\');
+ if (p) {
+ st->print("%s", p + 1);
+ } else {
+ st->print("%s", buf);
+ }
+ } else {
+ // The library name is probably truncated. Let's omit the library name.
+ // See also JDK-8147512.
+ }
+ if (os::dll_address_to_function_name(addr, buf, sizeof(buf), &offset)) {
+ st->print("::%s + 0x%x", buf, offset);
+ }
+ st->cr();
+ result = true;
+ }
+ return result;
}
LONG WINAPI os::win32::serialize_fault_filter(struct _EXCEPTION_POINTERS* e) {
--- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -599,6 +599,7 @@
// this is only for the "general purpose" registers
#ifdef AMD64
+ st->print("RIP="); print_location(st, uc->Rip);
st->print("RAX="); print_location(st, uc->Rax);
st->print("RBX="); print_location(st, uc->Rbx);
st->print("RCX="); print_location(st, uc->Rcx);
@@ -616,6 +617,7 @@
st->print("R14="); print_location(st, uc->R14);
st->print("R15="); print_location(st, uc->R15);
#else
+ st->print("EIP="); print_location(st, uc->Eip);
st->print("EAX="); print_location(st, uc->Eax);
st->print("EBX="); print_location(st, uc->Ebx);
st->print("ECX="); print_location(st, uc->Ecx);
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -2972,8 +2972,8 @@
SharedRuntime::get_resolve_virtual_call_stub(),
arg_list, info);
} else {
- int entry_offset = InstanceKlass::vtable_start_offset() + x->vtable_index() * vtableEntry::size();
- int vtable_offset = entry_offset * wordSize + vtableEntry::method_offset_in_bytes();
+ int entry_offset = in_bytes(Klass::vtable_start_offset()) + x->vtable_index() * vtableEntry::size_in_bytes();
+ int vtable_offset = entry_offset + vtableEntry::method_offset_in_bytes();
__ call_virtual(target, receiver, result_register, vtable_offset, arg_list, info);
}
break;
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -34,6 +34,7 @@
#include "classfile/verifier.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc/shared/gcLocker.hpp"
+#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/oopFactory.hpp"
@@ -79,7 +80,7 @@
#define JAVA_CLASSFILE_MAGIC 0xCAFEBABE
#define JAVA_MIN_SUPPORTED_VERSION 45
-#define JAVA_MAX_SUPPORTED_VERSION 52
+#define JAVA_MAX_SUPPORTED_VERSION 53
#define JAVA_MAX_SUPPORTED_MINOR_VERSION 0
// Used for two backward compatibility reasons:
@@ -100,6 +101,8 @@
// Extension method support.
#define JAVA_8_VERSION 52
+#define JAVA_9_VERSION 53
+
enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names
void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const stream,
@@ -2705,7 +2708,7 @@
ConstMethod::NORMAL,
CHECK_NULL);
- ClassLoadingService::add_class_method_size(m->size()*HeapWordSize);
+ ClassLoadingService::add_class_method_size(m->size()*wordSize);
// Fill in information from fixed part (access_flags already set)
m->set_constants(_cp);
@@ -4602,8 +4605,8 @@
}
} else if (major_gte_15) {
// Class file version in the interval [JAVA_1_5_VERSION, JAVA_8_VERSION)
- if (!is_public || is_static || is_final || is_synchronized ||
- is_native || !is_abstract || is_strict) {
+ if (!is_public || is_private || is_protected || is_static || is_final ||
+ is_synchronized || is_native || !is_abstract || is_strict) {
is_illegal = true;
}
} else {
@@ -5347,30 +5350,12 @@
ClassLoadingService::notify_class_loaded(ik, false /* not shared class */);
if (!is_internal()) {
- if (TraceClassLoading) {
- ResourceMark rm;
- // print in a single call to reduce interleaving of output
- if (_stream->source() != NULL) {
- tty->print("[Loaded %s from %s]\n",
- ik->external_name(),
- _stream->source());
- } else if (_loader_data->class_loader() == NULL) {
- const Klass* const caller =
- THREAD->is_Java_thread()
- ? ((JavaThread*)THREAD)->security_get_caller_class(1)
- : NULL;
- // caller can be NULL, for example, during a JVMTI VM_Init hook
- if (caller != NULL) {
- tty->print("[Loaded %s by instance of %s]\n",
- ik->external_name(),
- caller->external_name());
- } else {
- tty->print("[Loaded %s]\n", ik->external_name());
- }
- } else {
- tty->print("[Loaded %s from %s]\n", ik->external_name(),
- _loader_data->class_loader()->klass()->external_name());
- }
+ if (log_is_enabled(Info, classload)) {
+ ik->print_loading_log(LogLevel::Info, _loader_data, _stream);
+ }
+ // No 'else' here as logging levels are not mutually exclusive
+ if (log_is_enabled(Debug, classload)) {
+ ik->print_loading_log(LogLevel::Debug, _loader_data, _stream);
}
if (log_is_enabled(Info, classresolve)) {
--- a/hotspot/src/share/vm/classfile/classLoader.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -578,15 +578,14 @@
}
}
}
- if (TraceClassLoading || TraceClassPaths) {
+ if (TraceClassPaths) {
tty->print_cr("[Opened %s]", path);
}
+ log_info(classload)("opened: %s", path);
} else {
// Directory
new_entry = new ClassPathDirEntry(path);
- if (TraceClassLoading) {
- tty->print_cr("[Path %s]", path);
- }
+ log_info(classload)("path: %s", path);
}
return new_entry;
}
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -54,12 +54,14 @@
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/shared/gcLocker.hpp"
+#include "logging/log.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomic.inline.hpp"
+#include "runtime/javaCalls.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/mutex.hpp"
#include "runtime/safepoint.hpp"
@@ -286,9 +288,9 @@
_klasses = k;
}
- if (publicize && TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
+ if (publicize && k->class_loader_data() != NULL) {
ResourceMark rm;
- tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
+ log_trace(classloaderdata)("Adding k: " PTR_FORMAT " %s to CLD: "
PTR_FORMAT " loader: " PTR_FORMAT " %s",
p2i(k),
k->external_name(),
@@ -326,15 +328,16 @@
// Tell serviceability tools these classes are unloading
classes_do(InstanceKlass::notify_unload_class);
- if (TraceClassLoaderData) {
+ if (log_is_enabled(Debug, classloaderdata)) {
ResourceMark rm;
- tty->print("[ClassLoaderData: unload loader data " INTPTR_FORMAT, p2i(this));
- tty->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)class_loader()),
+ outputStream* log = LogHandle(classloaderdata)::debug_stream();
+ log->print(": unload loader data " INTPTR_FORMAT, p2i(this));
+ log->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)class_loader()),
loader_name());
if (is_anonymous()) {
- tty->print(" for anonymous class " INTPTR_FORMAT " ", p2i(_klasses));
+ log->print(" for anonymous class " INTPTR_FORMAT " ", p2i(_klasses));
}
- tty->print_cr("]");
+ log->cr();
}
}
@@ -408,13 +411,13 @@
assert (class_loader() == NULL, "Must be");
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType));
} else if (is_anonymous()) {
- if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
- tty->print_cr("is_anonymous: %s", class_loader()->klass()->internal_name());
+ if (class_loader() != NULL) {
+ log_trace(classloaderdata)("is_anonymous: %s", class_loader()->klass()->internal_name());
}
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType));
} else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
- if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
- tty->print_cr("is_reflection: %s", class_loader()->klass()->internal_name());
+ if (class_loader() != NULL) {
+ log_trace(classloaderdata)("is_reflection: %s", class_loader()->klass()->internal_name());
}
set_metaspace(new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType));
} else {
@@ -601,21 +604,47 @@
cld->set_next(next);
ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
if (exchanged == next) {
- if (TraceClassLoaderData) {
- ResourceMark rm;
- tty->print("[ClassLoaderData: ");
- tty->print("create class loader data " INTPTR_FORMAT, p2i(cld));
- tty->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()),
- cld->loader_name());
- tty->print_cr("]");
+ if (log_is_enabled(Debug, classloaderdata)) {
+ PauseNoSafepointVerifier pnsv(&no_safepoints); // Need safe points for JavaCalls::call_virtual
+ log_creation(loader, cld, CHECK_NULL);
}
return cld;
}
next = exchanged;
} while (true);
+}
+void ClassLoaderDataGraph::log_creation(Handle loader, ClassLoaderData* cld, TRAPS) {
+ Handle string;
+ if (loader.not_null()) {
+ // Include the result of loader.toString() in the output. This allows
+ // the user of the log to identify the class loader instance.
+ JavaValue result(T_OBJECT);
+ KlassHandle spec_klass(THREAD, SystemDictionary::ClassLoader_klass());
+ JavaCalls::call_virtual(&result,
+ loader,
+ spec_klass,
+ vmSymbols::toString_name(),
+ vmSymbols::void_string_signature(),
+ CHECK);
+ assert(result.get_type() == T_OBJECT, "just checking");
+ string = (oop)result.get_jobject();
+ }
+
+ ResourceMark rm;
+ outputStream* log = LogHandle(classloaderdata)::debug_stream();
+ log->print("create class loader data " INTPTR_FORMAT, p2i(cld));
+ log->print(" for instance " INTPTR_FORMAT " of %s", p2i((void *)cld->class_loader()),
+ cld->loader_name());
+
+ if (string.not_null()) {
+ log->print(": ");
+ java_lang_String::print(string(), log);
+ }
+ log->cr();
}
+
void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
cld->oops_do(f, klass_closure, must_claim);
@@ -709,10 +738,11 @@
if (!curr->claimed()) {
array->push(curr);
- if (TraceClassLoaderData) {
- tty->print("[ClassLoaderData] found new CLD: ");
- curr->print_value_on(tty);
- tty->cr();
+ if (log_is_enabled(Debug, classloaderdata)) {
+ outputStream* log = LogHandle(classloaderdata)::debug_stream();
+ log->print("found new CLD: ");
+ curr->print_value_on(log);
+ log->cr();
}
}
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -116,6 +116,7 @@
static void dump_on(outputStream * const out) PRODUCT_RETURN;
static void dump() { dump_on(tty); }
static void verify();
+ static void log_creation(Handle loader, ClassLoaderData* cld, TRAPS);
static bool unload_list_contains(const void* x);
#ifndef PRODUCT
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -365,14 +365,14 @@
}
int HashtableTextDump::skip(char must_be_char) {
- corrupted_if(remain() < 1);
- corrupted_if(*_p++ != must_be_char);
+ corrupted_if(remain() < 1, "Truncated");
+ corrupted_if(*_p++ != must_be_char, "Unexpected character");
return 0;
}
void HashtableTextDump::skip_past(char c) {
for (;;) {
- corrupted_if(remain() < 1);
+ corrupted_if(remain() < 1, "Truncated");
if (*_p++ == c) {
return;
}
@@ -381,7 +381,7 @@
void HashtableTextDump::check_version(const char* ver) {
int len = (int)strlen(ver);
- corrupted_if(remain() < len);
+ corrupted_if(remain() < len, "Truncated");
if (strncmp(_p, ver, len) != 0) {
quit("wrong version of hashtable dump file", _filename);
}
@@ -451,7 +451,7 @@
jchar HashtableTextDump::unescape(const char* from, const char* end, int count) {
jchar value = 0;
- corrupted_if(from + count > end);
+ corrupted_if(from + count > end, "Truncated");
for (int i=0; i<count; i++) {
char c = *from++;
@@ -486,7 +486,7 @@
if (*from != '\\') {
*to++ = *from++;
} else {
- corrupted_if(from + 2 > end);
+ corrupted_if(from + 2 > end, "Truncated");
char c = from[1];
from += 2;
switch (c) {
@@ -507,7 +507,7 @@
}
}
}
- corrupted_if(n > 0); // expected more chars but file has ended
+ corrupted_if(n > 0, "Truncated"); // expected more chars but file has ended
_p = from;
skip_newline();
}
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -276,9 +276,9 @@
void corrupted(const char *p, const char *msg);
- inline void corrupted_if(bool cond) {
+ inline void corrupted_if(bool cond, const char *msg) {
if (cond) {
- corrupted(_p, NULL);
+ corrupted(_p, msg);
}
}
@@ -287,27 +287,30 @@
void skip_past(char c);
void check_version(const char* ver);
- inline bool get_num(char delim, int *utf8_length) {
+ inline void get_num(char delim, int *num) {
const char* p = _p;
const char* end = _end;
- int num = 0;
+ u8 n = 0;
while (p < end) {
char c = *p ++;
if ('0' <= c && c <= '9') {
- num = num * 10 + (c - '0');
+ n = n * 10 + (c - '0');
+ if (n > (u8)INT_MAX) {
+ corrupted(_p, "Num overflow");
+ }
} else if (c == delim) {
_p = p;
- *utf8_length = num;
- return true;
+ *num = (int)n;
+ return;
} else {
// Not [0-9], not 'delim'
- return false;
+ corrupted(_p, "Unrecognized format");;
}
}
+
corrupted(_end, "Incorrect format");
ShouldNotReachHere();
- return false;
}
void scan_prefix_type();
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -129,7 +129,7 @@
tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int());
}
#endif //PRODUCT
- vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
+ vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:classload=info to see the origin of the problem class");
}
dest_offset = fd.offset();
}
@@ -3972,7 +3972,7 @@
tty->print_cr(" name: %s, sig: %s, flags: %08x", fs.name()->as_C_string(), fs.signature()->as_C_string(), fs.access_flags().as_int());
}
#endif //PRODUCT
- vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
+ vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:classload=info to see the origin of the problem class");
return -1;
}
--- a/hotspot/src/share/vm/classfile/stringTable.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -737,7 +737,7 @@
return false;
}
ch_table.dump(top, end);
- *top = (char*)align_pointer_up(*top, sizeof(void*));
+ *top = (char*)align_ptr_up(*top, sizeof(void*));
#endif
return true;
@@ -760,7 +760,7 @@
juint *p = (juint*)buffer;
const char* end = _shared_table.init(
CompactHashtable<oop, char>::_string_table, (char*)p);
- const char* aligned_end = (const char*)align_pointer_up(end, sizeof(void*));
+ const char* aligned_end = (const char*)align_ptr_up(end, sizeof(void*));
if (_ignore_shared_strings) {
_shared_table.reset();
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -544,7 +544,7 @@
ch_table.dump(top, end);
- *top = (char*)align_pointer_up(*top, sizeof(void*));
+ *top = (char*)align_ptr_up(*top, sizeof(void*));
#endif
return true;
}
@@ -552,7 +552,7 @@
const char* SymbolTable::init_shared_table(const char* buffer) {
const char* end = _shared_table.init(
CompactHashtable<Symbol*, char>::_symbol_table, buffer);
- return (const char*)align_pointer_up(end, sizeof(void*));
+ return (const char*)align_ptr_up(end, sizeof(void*));
}
//---------------------------------------------------------------------------
@@ -600,7 +600,7 @@
tty->print_cr("Symbol Table Histogram:");
tty->print_cr(" Total number of symbols %7d", total_count);
tty->print_cr(" Total size in memory %7dK",
- (total_size*HeapWordSize)/1024);
+ (total_size*wordSize)/1024);
tty->print_cr(" Total counted %7d", _symbols_counted);
tty->print_cr(" Total removed %7d", _symbols_removed);
if (_symbols_counted > 0) {
@@ -617,11 +617,11 @@
tty->print_cr(" %6s %10s %10s", "Length", "#Symbols", "Size");
for (i = 0; i < results_length; i++) {
if (counts[i] > 0) {
- tty->print_cr(" %6d %10d %10dK", i, counts[i], (sizes[i]*HeapWordSize)/1024);
+ tty->print_cr(" %6d %10d %10dK", i, counts[i], (sizes[i]*wordSize)/1024);
}
}
tty->print_cr(" >=%6d %10d %10dK\n", results_length,
- out_of_range_count, (out_of_range_size*HeapWordSize)/1024);
+ out_of_range_count, (out_of_range_size*wordSize)/1024);
}
void SymbolTable::print() {
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1302,14 +1302,13 @@
ik->restore_unshareable_info(loader_data, protection_domain, CHECK_(nh));
}
- if (TraceClassLoading) {
- ResourceMark rm;
- tty->print("[Loaded %s", ik->external_name());
- tty->print(" from shared objects file");
- if (class_loader.not_null()) {
- tty->print(" by %s", loader_data->loader_name());
- }
- tty->print_cr("]");
+ if (log_is_enabled(Info, classload)) {
+ ik()->print_loading_log(LogLevel::Info, loader_data, NULL);
+ }
+ // No 'else' here as logging levels are not mutually exclusive
+
+ if (log_is_enabled(Debug, classload)) {
+ ik()->print_loading_log(LogLevel::Debug, loader_data, NULL);
}
if (DumpLoadedClassList != NULL && classlist_file->is_open()) {
--- a/hotspot/src/share/vm/classfile/verifier.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, 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
@@ -651,6 +651,7 @@
int ex_max = -1;
// Look through each item on the exception table. Each of the fields must refer
// to a legal instruction.
+ if (was_recursively_verified()) return;
verify_exception_handler_table(
code_length, code_data, ex_min, ex_max, CHECK_VERIFY(this));
@@ -737,11 +738,14 @@
// should be used for this check. So, do the check here before a possible
// local is added to the type state.
if (Bytecodes::is_store_into_local(opcode) && bci >= ex_min && bci < ex_max) {
+ if (was_recursively_verified()) return;
verify_exception_handler_targets(
bci, this_uninit, ¤t_frame, &stackmap_table, CHECK_VERIFY(this));
verified_exc_handlers = true;
}
+ if (was_recursively_verified()) return;
+
switch (opcode) {
case Bytecodes::_nop :
no_control_flow = false; break;
@@ -1730,6 +1734,7 @@
assert(!(verified_exc_handlers && this_uninit),
"Exception handler targets got verified before this_uninit got set");
if (!verified_exc_handlers && bci >= ex_min && bci < ex_max) {
+ if (was_recursively_verified()) return;
verify_exception_handler_targets(
bci, this_uninit, ¤t_frame, &stackmap_table, CHECK_VERIFY(this));
}
@@ -1767,6 +1772,9 @@
return code_data;
}
+// Since this method references the constant pool, call was_recursively_verified()
+// before calling this method to make sure a prior class load did not cause the
+// current class to get verified.
void ClassVerifier::verify_exception_handler_table(u4 code_length, char* code_data, int& min, int& max, TRAPS) {
ExceptionTable exhandlers(_method());
int exlength = exhandlers.length();
@@ -1874,7 +1882,11 @@
return stackmap_index;
}
-void ClassVerifier::verify_exception_handler_targets(u2 bci, bool this_uninit, StackMapFrame* current_frame,
+// Since this method references the constant pool, call was_recursively_verified()
+// before calling this method to make sure a prior class load did not cause the
+// current class to get verified.
+void ClassVerifier::verify_exception_handler_targets(u2 bci, bool this_uninit,
+ StackMapFrame* current_frame,
StackMapTable* stackmap_table, TRAPS) {
constantPoolHandle cp (THREAD, _method->constants());
ExceptionTable exhandlers(_method());
@@ -1889,6 +1901,7 @@
if (this_uninit) { flags |= FLAG_THIS_UNINIT; }
StackMapFrame* new_frame = current_frame->frame_in_exception_handler(flags);
if (catch_type_index != 0) {
+ if (was_recursively_verified()) return;
// We know that this index refers to a subclass of Throwable
VerificationType catch_type = cp_index_to_type(
catch_type_index, cp, CHECK_VERIFY(this));
@@ -2269,6 +2282,7 @@
check_protected: {
if (_this_type == stack_object_type)
break; // stack_object_type must be assignable to _current_class_type
+ if (was_recursively_verified()) return;
Symbol* ref_class_name =
cp->klass_name_at(cp->klass_ref_index_at(index));
if (!name_in_supers(ref_class_name, current_class()))
@@ -2531,6 +2545,7 @@
// Check the exception handler target stackmaps with the locals from the
// incoming stackmap (before initialize_object() changes them to outgoing
// state).
+ if (was_recursively_verified()) return;
verify_exception_handler_targets(bci, true, current_frame,
stackmap_table, CHECK_VERIFY(this));
} // in_try_block
@@ -2548,6 +2563,7 @@
return;
}
u2 new_class_index = Bytes::get_Java_u2(new_bcp + 1);
+ if (was_recursively_verified()) return;
verify_cp_class_type(bci, new_class_index, cp, CHECK_VERIFY(this));
// The method must be an <init> method of the indicated class
@@ -2567,6 +2583,7 @@
VerificationType objectref_type = new_class_type;
if (name_in_supers(ref_class_type.name(), current_class())) {
Klass* ref_klass = load_class(ref_class_type.name(), CHECK);
+ if (was_recursively_verified()) return;
Method* m = InstanceKlass::cast(ref_klass)->uncached_lookup_method(
vmSymbols::object_initializer_name(),
cp->signature_ref_at(bcs->get_index_u2()),
@@ -2591,6 +2608,7 @@
// incoming stackmap (before initialize_object() changes them to outgoing
// state).
if (in_try_block) {
+ if (was_recursively_verified()) return;
verify_exception_handler_targets(bci, *this_uninit, current_frame,
stackmap_table, CHECK_VERIFY(this));
}
@@ -2791,6 +2809,7 @@
verify_invoke_init(bcs, index, ref_class_type, current_frame,
code_length, in_try_block, this_uninit, cp, stackmap_table,
CHECK_VERIFY(this));
+ if (was_recursively_verified()) return;
} else { // other methods
// Ensures that target class is assignable to method class.
if (opcode == Bytecodes::_invokespecial) {
@@ -2816,6 +2835,7 @@
VerificationType stack_object_type =
current_frame->pop_stack(ref_class_type, CHECK_VERIFY(this));
if (current_type() != stack_object_type) {
+ if (was_recursively_verified()) return;
assert(cp->cache() == NULL, "not rewritten yet");
Symbol* ref_class_name =
cp->klass_name_at(cp->klass_ref_index_at(index));
@@ -2894,6 +2914,7 @@
current_frame->pop_stack(
VerificationType::integer_type(), CHECK_VERIFY(this));
+ if (was_recursively_verified()) return;
VerificationType component_type =
cp_index_to_type(index, cp, CHECK_VERIFY(this));
int length;
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -109,13 +109,13 @@
template(java_io_ByteArrayInputStream, "java/io/ByteArrayInputStream") \
template(java_io_Serializable, "java/io/Serializable") \
template(java_util_Arrays, "java/util/Arrays") \
- template(java_util_Objects, "java/util/Objects") \
+ template(java_util_Objects, "java/util/Objects") \
template(java_util_Properties, "java/util/Properties") \
template(java_util_Vector, "java/util/Vector") \
template(java_util_AbstractList, "java/util/AbstractList") \
template(java_util_Hashtable, "java/util/Hashtable") \
template(java_lang_Compiler, "java/lang/Compiler") \
- template(sun_misc_Signal, "sun/misc/Signal") \
+ template(jdk_internal_misc_Signal, "jdk/internal/misc/Signal") \
template(sun_misc_Launcher, "sun/misc/Launcher") \
template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \
template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \
--- a/hotspot/src/share/vm/code/codeCache.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1494,7 +1494,7 @@
}
void CodeCache::print_codelist(outputStream* st) {
- assert_locked_or_safepoint(CodeCache_lock);
+ MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
NMethodIterator iter;
while(iter.next_alive()) {
@@ -1508,9 +1508,8 @@
}
void CodeCache::print_layout(outputStream* st) {
- assert_locked_or_safepoint(CodeCache_lock);
+ MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
ResourceMark rm;
-
print_summary(st, true);
}
--- a/hotspot/src/share/vm/code/nmethod.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/code/nmethod.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -48,6 +48,7 @@
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#include "utilities/xmlstream.hpp"
+#include "logging/log.hpp"
#ifdef TARGET_ARCH_x86
# include "nativeInst_x86.hpp"
#endif
@@ -321,9 +322,12 @@
bool ExceptionCache::add_address_and_handler(address addr, address handler) {
if (test_address(addr) == handler) return true;
- if (count() < cache_size) {
- set_pc_at(count(),addr);
- set_handler_at(count(), handler);
+
+ int index = count();
+ if (index < cache_size) {
+ set_pc_at(index, addr);
+ set_handler_at(index, handler);
+ OrderAccess::storestore();
increment_count();
return true;
}
@@ -1310,13 +1314,14 @@
flush_dependencies(is_alive);
// Break cycle between nmethod & method
- if (TraceClassUnloading && WizardMode) {
- tty->print_cr("[Class unloading: Making nmethod " INTPTR_FORMAT
- " unloadable], Method*(" INTPTR_FORMAT
+ if (log_is_enabled(Trace, classunload)) {
+ outputStream* log = LogHandle(classunload)::trace_stream();
+ log->print_cr("making nmethod " INTPTR_FORMAT
+ " unloadable, Method*(" INTPTR_FORMAT
"), cause(" INTPTR_FORMAT ")",
p2i(this), p2i(_method), p2i(cause));
if (!Universe::heap()->is_gc_active())
- cause->klass()->print();
+ cause->klass()->print_on(log);
}
// Unlink the osr method, so we do not look this up again
if (is_osr_method()) {
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -466,9 +466,16 @@
return NULL;
}
+void CompileBroker::print_compile_queues(outputStream* st) {
+ st->print_cr("Current compiles: ");
+ MutexLocker locker(MethodCompileQueue_lock);
+ MutexLocker locker2(Threads_lock);
-void CompileBroker::print_compile_queues(outputStream* st) {
- MutexLocker locker(MethodCompileQueue_lock);
+ char buf[2000];
+ int buflen = sizeof(buf);
+ Threads::print_threads_compiling(st, buf, buflen);
+
+ st->cr();
if (_c1_compile_queue != NULL) {
_c1_compile_queue->print(st);
}
@@ -479,8 +486,7 @@
void CompileQueue::print(outputStream* st) {
assert(MethodCompileQueue_lock->owned_by_self(), "must own lock");
- st->print_cr("Contents of %s", name());
- st->print_cr("----------------------------");
+ st->print_cr("%s:", name());
CompileTask* task = _first;
if (task == NULL) {
st->print_cr("Empty");
@@ -490,7 +496,7 @@
task = task->next();
}
}
- st->print_cr("----------------------------");
+ st->cr();
}
void CompileQueue::print_tty() {
@@ -539,7 +545,7 @@
c1_count = JVMCIHostThreads;
}
- if (!UseInterpreter) {
+ if (!UseInterpreter || !BackgroundCompilation) {
// Force initialization of JVMCI compiler otherwise JVMCI
// compilations will not block until JVMCI is initialized
ResourceMark rm;
@@ -1340,49 +1346,55 @@
}
#if INCLUDE_JVMCI
-// The number of milliseconds to wait before checking if the
-// JVMCI compiler thread is blocked.
-static const long BLOCKING_JVMCI_COMPILATION_WAIT_TIMESLICE = 500;
+// The number of milliseconds to wait before checking if
+// JVMCI compilation has made progress.
+static const long JVMCI_COMPILATION_PROGRESS_WAIT_TIMESLICE = 500;
-// The number of successive times the above check is allowed to
-// see a blocked JVMCI compiler thread before unblocking the
-// thread waiting for the compilation to finish.
-static const int BLOCKING_JVMCI_COMPILATION_WAIT_TO_UNBLOCK_ATTEMPTS = 5;
+// The number of JVMCI compilation progress checks that must fail
+// before unblocking a thread waiting for a blocking compilation.
+static const int JVMCI_COMPILATION_PROGRESS_WAIT_ATTEMPTS = 5;
/**
* Waits for a JVMCI compiler to complete a given task. This thread
- * waits until either the task completes or it sees the JVMCI compiler
- * thread is blocked for N consecutive milliseconds where N is
- * BLOCKING_JVMCI_COMPILATION_WAIT_TIMESLICE *
- * BLOCKING_JVMCI_COMPILATION_WAIT_TO_UNBLOCK_ATTEMPTS.
+ * waits until either the task completes or it sees no JVMCI compilation
+ * progress for N consecutive milliseconds where N is
+ * JVMCI_COMPILATION_PROGRESS_WAIT_TIMESLICE *
+ * JVMCI_COMPILATION_PROGRESS_WAIT_ATTEMPTS.
*
* @return true if this thread needs to free/recycle the task
*/
-bool CompileBroker::wait_for_jvmci_completion(CompileTask* task, JavaThread* thread) {
+bool CompileBroker::wait_for_jvmci_completion(JVMCICompiler* jvmci, CompileTask* task, JavaThread* thread) {
MutexLocker waiter(task->lock(), thread);
- int consecutively_blocked = 0;
- while (task->lock()->wait(!Mutex::_no_safepoint_check_flag, BLOCKING_JVMCI_COMPILATION_WAIT_TIMESLICE)) {
+ int progress_wait_attempts = 0;
+ int methods_compiled = jvmci->methods_compiled();
+ while (!task->is_complete() && !is_compilation_disabled_forever() &&
+ task->lock()->wait(!Mutex::_no_safepoint_check_flag, JVMCI_COMPILATION_PROGRESS_WAIT_TIMESLICE)) {
CompilerThread* jvmci_compiler_thread = task->jvmci_compiler_thread();
+
+ bool progress;
if (jvmci_compiler_thread != NULL) {
- JavaThreadState state;
- {
- // A JVMCI compiler thread should not disappear at this point
- // but let's be extra safe.
- MutexLocker mu(Threads_lock, thread);
- state = jvmci_compiler_thread->thread_state();
- }
- if (state == _thread_blocked) {
- if (++consecutively_blocked == BLOCKING_JVMCI_COMPILATION_WAIT_TO_UNBLOCK_ATTEMPTS) {
- if (PrintCompilation) {
- task->print(tty, "wait for blocking compilation timed out");
- }
- break;
+ // If the JVMCI compiler thread is not blocked, we deem it to be making progress.
+ progress = jvmci_compiler_thread->thread_state() != _thread_blocked;
+ } else {
+ // Still waiting on JVMCI compiler queue. This thread may be holding a lock
+ // that all JVMCI compiler threads are blocked on. We use the counter for
+ // successful JVMCI compilations to determine whether JVMCI compilation
+ // is still making progress through the JVMCI compiler queue.
+ progress = jvmci->methods_compiled() != methods_compiled;
+ }
+
+ if (!progress) {
+ if (++progress_wait_attempts == JVMCI_COMPILATION_PROGRESS_WAIT_ATTEMPTS) {
+ if (PrintCompilation) {
+ task->print(tty, "wait for blocking compilation timed out");
}
- } else {
- consecutively_blocked = 0;
+ break;
}
} else {
- // Still waiting on JVMCI compiler queue
+ progress_wait_attempts = 0;
+ if (jvmci_compiler_thread == NULL) {
+ methods_compiled = jvmci->methods_compiled();
+ }
}
}
task->clear_waiter();
@@ -1407,8 +1419,9 @@
methodHandle method(thread, task->method());
bool free_task;
#if INCLUDE_JVMCI
- if (compiler(task->comp_level())->is_jvmci()) {
- free_task = wait_for_jvmci_completion(task, thread);
+ AbstractCompiler* comp = compiler(task->comp_level());
+ if (comp->is_jvmci()) {
+ free_task = wait_for_jvmci_completion((JVMCICompiler*) comp, task, thread);
} else
#endif
{
@@ -2355,10 +2368,3 @@
}
}
-
-void CompileBroker::print_compiler_threads_on(outputStream* st) {
-#ifndef PRODUCT
- st->print_cr("Compiler thread printing unimplemented.");
- st->cr();
-#endif
-}
--- a/hotspot/src/share/vm/compiler/compileBroker.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/compiler/compileBroker.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -32,6 +32,9 @@
#include "runtime/perfData.hpp"
#include "trace/tracing.hpp"
#include "utilities/stack.hpp"
+#if INCLUDE_JVMCI
+#include "jvmci/jvmciCompiler.hpp"
+#endif
class nmethod;
class nmethodLocker;
@@ -234,7 +237,7 @@
bool blocking);
static void wait_for_completion(CompileTask* task);
#if INCLUDE_JVMCI
- static bool wait_for_jvmci_completion(CompileTask* task, JavaThread* thread);
+ static bool wait_for_jvmci_completion(JVMCICompiler* comp, CompileTask* task, JavaThread* thread);
#endif
static void invoke_compiler_on_method(CompileTask* task);
@@ -350,8 +353,6 @@
// Debugging output for failure
static void print_last_compile();
- static void print_compiler_threads_on(outputStream* st);
-
// compiler name for debugging
static const char* compiler_name(int comp_level);
--- a/hotspot/src/share/vm/compiler/disassembler.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/compiler/disassembler.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -85,6 +85,7 @@
public:
static bool can_decode() {
+ ttyLocker tl;
return (_decode_instructions_virtual != NULL) ||
(_decode_instructions != NULL) ||
load_library();
--- a/hotspot/src/share/vm/gc/cms/cmsCollectorPolicy.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/cmsCollectorPolicy.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
#include "gc/shared/space.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "memory/universe.hpp"
+#include "oops/oop.inline.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/handles.inline.hpp"
--- a/hotspot/src/share/vm/gc/cms/cmsOopClosures.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/cmsOopClosures.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, 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
@@ -40,15 +40,9 @@
class ParMarkFromRootsClosure;
// Decode the oop and call do_oop on it.
-#define DO_OOP_WORK_DEFN \
- void do_oop(oop obj); \
- template <class T> inline void do_oop_work(T* p) { \
- T heap_oop = oopDesc::load_heap_oop(p); \
- if (!oopDesc::is_null(heap_oop)) { \
- oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); \
- do_oop(obj); \
- } \
- }
+#define DO_OOP_WORK_DEFN \
+ void do_oop(oop obj); \
+ template <class T> inline void do_oop_work(T* p);
// TODO: This duplication of the MetadataAwareOopClosure class is only needed
// because some CMS OopClosures derive from OopsInGenClosure. It would be
@@ -131,8 +125,8 @@
bool concurrent_precleaning);
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
- inline void do_oop_nv(oop* p) { PushAndMarkClosure::do_oop_work(p); }
- inline void do_oop_nv(narrowOop* p) { PushAndMarkClosure::do_oop_work(p); }
+ inline void do_oop_nv(oop* p);
+ inline void do_oop_nv(narrowOop* p);
};
// In the parallel case, the bit map and the
@@ -157,8 +151,8 @@
OopTaskQueue* work_queue);
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
- inline void do_oop_nv(oop* p) { ParPushAndMarkClosure::do_oop_work(p); }
- inline void do_oop_nv(narrowOop* p) { ParPushAndMarkClosure::do_oop_work(p); }
+ inline void do_oop_nv(oop* p);
+ inline void do_oop_nv(narrowOop* p);
};
// The non-parallel version (the parallel version appears further below).
@@ -186,8 +180,8 @@
bool concurrent_precleaning);
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
- inline void do_oop_nv(oop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); }
- inline void do_oop_nv(narrowOop* p) { MarkRefsIntoAndScanClosure::do_oop_work(p); }
+ inline void do_oop_nv(oop* p);
+ inline void do_oop_nv(narrowOop* p);
void set_freelistLock(Mutex* m) {
_freelistLock = m;
@@ -220,8 +214,8 @@
OopTaskQueue* work_queue);
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
- inline void do_oop_nv(oop* p) { ParMarkRefsIntoAndScanClosure::do_oop_work(p); }
- inline void do_oop_nv(narrowOop* p) { ParMarkRefsIntoAndScanClosure::do_oop_work(p); }
+ inline void do_oop_nv(oop* p);
+ inline void do_oop_nv(narrowOop* p);
void trim_queue(uint size);
};
@@ -249,8 +243,8 @@
MarkFromRootsClosure* parent);
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
- inline void do_oop_nv(oop* p) { PushOrMarkClosure::do_oop_work(p); }
- inline void do_oop_nv(narrowOop* p) { PushOrMarkClosure::do_oop_work(p); }
+ inline void do_oop_nv(oop* p);
+ inline void do_oop_nv(narrowOop* p);
// Deal with a stack overflow condition
void handle_stack_overflow(HeapWord* lost);
@@ -287,8 +281,8 @@
ParMarkFromRootsClosure* parent);
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
- inline void do_oop_nv(oop* p) { ParPushOrMarkClosure::do_oop_work(p); }
- inline void do_oop_nv(narrowOop* p) { ParPushOrMarkClosure::do_oop_work(p); }
+ inline void do_oop_nv(oop* p);
+ inline void do_oop_nv(narrowOop* p);
// Deal with a stack overflow condition
void handle_stack_overflow(HeapWord* lost);
@@ -318,8 +312,8 @@
bool concurrent_precleaning() const { return _concurrent_precleaning; }
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
- inline void do_oop_nv(oop* p) { CMSKeepAliveClosure::do_oop_work(p); }
- inline void do_oop_nv(narrowOop* p) { CMSKeepAliveClosure::do_oop_work(p); }
+ inline void do_oop_nv(oop* p);
+ inline void do_oop_nv(narrowOop* p);
};
class CMSInnerParMarkAndPushClosure: public MetadataAwareOopClosure {
@@ -336,8 +330,8 @@
OopTaskQueue* work_queue);
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
- inline void do_oop_nv(oop* p) { CMSInnerParMarkAndPushClosure::do_oop_work(p); }
- inline void do_oop_nv(narrowOop* p) { CMSInnerParMarkAndPushClosure::do_oop_work(p); }
+ inline void do_oop_nv(oop* p);
+ inline void do_oop_nv(narrowOop* p);
};
// A parallel (MT) version of the above, used when
--- a/hotspot/src/share/vm/gc/cms/cmsOopClosures.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/cmsOopClosures.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, 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
@@ -30,21 +30,6 @@
#include "gc/shared/taskqueue.inline.hpp"
#include "oops/oop.inline.hpp"
-// Trim our work_queue so its length is below max at return
-inline void ParMarkRefsIntoAndScanClosure::trim_queue(uint max) {
- while (_work_queue->size() > max) {
- oop newOop;
- if (_work_queue->pop_local(newOop)) {
- assert(newOop->is_oop(), "Expected an oop");
- assert(_bit_map->isMarked((HeapWord*)newOop),
- "only grey objects on this stack");
- // iterate over the oops in this oop, marking and pushing
- // the ones in CMS heap (i.e. in _span).
- newOop->oop_iterate(&_parPushAndMarkClosure);
- }
- }
-}
-
// MetadataAwareOopClosure and MetadataAwareOopsInGenClosure are duplicated,
// until we get rid of OopsInGenClosure.
@@ -61,4 +46,48 @@
cld->oops_do(_klass_closure._oop_closure, &_klass_closure, claim);
}
+// Decode the oop and call do_oop on it.
+#define DO_OOP_WORK_IMPL(cls) \
+ template <class T> void cls::do_oop_work(T* p) { \
+ T heap_oop = oopDesc::load_heap_oop(p); \
+ if (!oopDesc::is_null(heap_oop)) { \
+ oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); \
+ do_oop(obj); \
+ } \
+ }
+
+#define DO_OOP_WORK_NV_IMPL(cls) \
+ DO_OOP_WORK_IMPL(cls) \
+ void cls::do_oop_nv(oop* p) { cls::do_oop_work(p); } \
+ void cls::do_oop_nv(narrowOop* p) { cls::do_oop_work(p); }
+
+DO_OOP_WORK_IMPL(MarkRefsIntoClosure)
+DO_OOP_WORK_IMPL(ParMarkRefsIntoClosure)
+DO_OOP_WORK_IMPL(MarkRefsIntoVerifyClosure)
+DO_OOP_WORK_NV_IMPL(PushAndMarkClosure)
+DO_OOP_WORK_NV_IMPL(ParPushAndMarkClosure)
+DO_OOP_WORK_NV_IMPL(MarkRefsIntoAndScanClosure)
+DO_OOP_WORK_NV_IMPL(ParMarkRefsIntoAndScanClosure)
+
+// Trim our work_queue so its length is below max at return
+inline void ParMarkRefsIntoAndScanClosure::trim_queue(uint max) {
+ while (_work_queue->size() > max) {
+ oop newOop;
+ if (_work_queue->pop_local(newOop)) {
+ assert(newOop->is_oop(), "Expected an oop");
+ assert(_bit_map->isMarked((HeapWord*)newOop),
+ "only grey objects on this stack");
+ // iterate over the oops in this oop, marking and pushing
+ // the ones in CMS heap (i.e. in _span).
+ newOop->oop_iterate(&_parPushAndMarkClosure);
+ }
+ }
+}
+
+DO_OOP_WORK_NV_IMPL(PushOrMarkClosure)
+DO_OOP_WORK_NV_IMPL(ParPushOrMarkClosure)
+DO_OOP_WORK_NV_IMPL(CMSKeepAliveClosure)
+DO_OOP_WORK_NV_IMPL(CMSInnerParMarkAndPushClosure)
+DO_OOP_WORK_IMPL(CMSParKeepAliveClosure)
+
#endif // SHARE_VM_GC_CMS_CMSOOPCLOSURES_INLINE_HPP
--- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -219,6 +219,10 @@
}
}
+size_t CompactibleFreeListSpace::obj_size(const HeapWord* addr) const {
+ return adjustObjectSize(oop(addr)->size());
+}
+
void CompactibleFreeListSpace::resetIndexedFreeListArray() {
for (size_t i = 1; i < IndexSetSize; i++) {
assert(_indexedFreeList[i].size() == (size_t) i,
--- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -313,9 +313,7 @@
return adjustObjectSize(size);
}
- inline size_t obj_size(const HeapWord* addr) const {
- return adjustObjectSize(oop(addr)->size());
- }
+ inline size_t obj_size(const HeapWord* addr) const;
protected:
// Reset the indexed free list to its initial empty condition.
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -1517,6 +1517,8 @@
SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer();
gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
+ gch->pre_full_gc_dump(gc_timer);
+
GCTraceTime(Trace, gc) t("CMS:MSC");
// Temporarily widen the span of the weak reference processing to
@@ -1593,6 +1595,8 @@
_inter_sweep_timer.reset();
_inter_sweep_timer.start();
+ gch->post_full_gc_dump(gc_timer);
+
gc_timer->register_gc_end();
gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
@@ -3324,6 +3328,8 @@
}
};
+DO_OOP_WORK_IMPL(ParConcMarkingClosure)
+
// Grey object scanning during work stealing phase --
// the salient assumption here is that any references
// that are in these stolen objects being scanned must
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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,7 +29,7 @@
#include "gc/cms/parOopClosures.inline.hpp"
#include "gc/serial/defNewGeneration.inline.hpp"
#include "gc/shared/adaptiveSizePolicy.hpp"
-#include "gc/shared/ageTable.hpp"
+#include "gc/shared/ageTable.inline.hpp"
#include "gc/shared/copyFailedInfo.hpp"
#include "gc/shared/gcHeapSummary.hpp"
#include "gc/shared/gcTimer.hpp"
@@ -414,7 +414,7 @@
}
void ParScanThreadStateSet::print_taskqueue_stats() {
- if (!develop_log_is_enabled(Trace, gc, task, stats)) {
+ if (!log_develop_is_enabled(Trace, gc, task, stats)) {
return;
}
LogHandle(gc, task, stats) log;
--- a/hotspot/src/share/vm/gc/cms/promotionInfo.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/promotionInfo.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, 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
@@ -34,6 +34,31 @@
/////////////////////////////////////////////////////////////////////////
+PromotedObject* PromotedObject::next() const {
+ assert(!((FreeChunk*)this)->is_free(), "Error");
+ PromotedObject* res;
+ if (UseCompressedOops) {
+ // The next pointer is a compressed oop stored in the top 32 bits
+ res = (PromotedObject*)oopDesc::decode_heap_oop(_data._narrow_next);
+ } else {
+ res = (PromotedObject*)(_next & next_mask);
+ }
+ assert(oop(res)->is_oop_or_null(true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(res)));
+ return res;
+}
+
+inline void PromotedObject::setNext(PromotedObject* x) {
+ assert(((intptr_t)x & ~next_mask) == 0, "Conflict in bit usage, "
+ "or insufficient alignment of objects");
+ if (UseCompressedOops) {
+ assert(_data._narrow_next == 0, "Overwrite?");
+ _data._narrow_next = oopDesc::encode_heap_oop(oop(x));
+ } else {
+ _next |= (intptr_t)x;
+ }
+ assert(!((FreeChunk*)this)->is_free(), "Error");
+}
+
//////////////////////////////////////////////////////////////////////////////
// We go over the list of promoted objects, removing each from the list,
// and applying the closure (this may, in turn, add more elements to
--- a/hotspot/src/share/vm/gc/cms/promotionInfo.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/cms/promotionInfo.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, 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
@@ -64,29 +64,8 @@
Data _data;
};
public:
- inline PromotedObject* next() const {
- assert(!((FreeChunk*)this)->is_free(), "Error");
- PromotedObject* res;
- if (UseCompressedOops) {
- // The next pointer is a compressed oop stored in the top 32 bits
- res = (PromotedObject*)oopDesc::decode_heap_oop(_data._narrow_next);
- } else {
- res = (PromotedObject*)(_next & next_mask);
- }
- assert(oop(res)->is_oop_or_null(true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(oop(res)));
- return res;
- }
- inline void setNext(PromotedObject* x) {
- assert(((intptr_t)x & ~next_mask) == 0, "Conflict in bit usage, "
- "or insufficient alignment of objects");
- if (UseCompressedOops) {
- assert(_data._narrow_next == 0, "Overwrite?");
- _data._narrow_next = oopDesc::encode_heap_oop(oop(x));
- } else {
- _next |= (intptr_t)x;
- }
- assert(!((FreeChunk*)this)->is_free(), "Error");
- }
+ PromotedObject* next() const;
+ void setNext(PromotedObject* x);
inline void setPromotedMark() {
_next |= promoted_mask;
assert(!((FreeChunk*)this)->is_free(), "Error");
--- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -59,10 +59,10 @@
_monitor = DirtyCardQ_CBL_mon;
}
initialize();
- create_and_start();
// set name
set_name("G1 Refine#%d", worker_id);
+ create_and_start();
}
void ConcurrentG1RefineThread::initialize() {
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Mon Feb 22 09:02:14 2016 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3681 +0,0 @@
-/*
- * Copyright (c) 2001, 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.
- *
- */
-
-#include "precompiled.hpp"
-#include "classfile/metadataOnStackMark.hpp"
-#include "classfile/symbolTable.hpp"
-#include "code/codeCache.hpp"
-#include "gc/g1/concurrentMark.inline.hpp"
-#include "gc/g1/concurrentMarkThread.inline.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/g1CollectorPolicy.hpp"
-#include "gc/g1/g1CollectorState.hpp"
-#include "gc/g1/g1OopClosures.inline.hpp"
-#include "gc/g1/g1StringDedup.hpp"
-#include "gc/g1/heapRegion.inline.hpp"
-#include "gc/g1/heapRegionRemSet.hpp"
-#include "gc/g1/heapRegionSet.inline.hpp"
-#include "gc/g1/suspendibleThreadSet.hpp"
-#include "gc/shared/gcId.hpp"
-#include "gc/shared/gcTimer.hpp"
-#include "gc/shared/gcTrace.hpp"
-#include "gc/shared/gcTraceTime.inline.hpp"
-#include "gc/shared/genOopClosures.inline.hpp"
-#include "gc/shared/referencePolicy.hpp"
-#include "gc/shared/strongRootsScope.hpp"
-#include "gc/shared/taskqueue.inline.hpp"
-#include "gc/shared/vmGCOperations.hpp"
-#include "logging/log.hpp"
-#include "memory/allocation.hpp"
-#include "memory/resourceArea.hpp"
-#include "oops/oop.inline.hpp"
-#include "runtime/atomic.inline.hpp"
-#include "runtime/handles.inline.hpp"
-#include "runtime/java.hpp"
-#include "runtime/prefetch.inline.hpp"
-#include "services/memTracker.hpp"
-
-// Concurrent marking bit map wrapper
-
-CMBitMapRO::CMBitMapRO(int shifter) :
- _bm(),
- _shifter(shifter) {
- _bmStartWord = 0;
- _bmWordSize = 0;
-}
-
-HeapWord* CMBitMapRO::getNextMarkedWordAddress(const HeapWord* addr,
- const HeapWord* limit) const {
- // First we must round addr *up* to a possible object boundary.
- addr = (HeapWord*)align_size_up((intptr_t)addr,
- HeapWordSize << _shifter);
- size_t addrOffset = heapWordToOffset(addr);
- assert(limit != NULL, "limit must not be NULL");
- size_t limitOffset = heapWordToOffset(limit);
- size_t nextOffset = _bm.get_next_one_offset(addrOffset, limitOffset);
- HeapWord* nextAddr = offsetToHeapWord(nextOffset);
- assert(nextAddr >= addr, "get_next_one postcondition");
- assert(nextAddr == limit || isMarked(nextAddr),
- "get_next_one postcondition");
- return nextAddr;
-}
-
-#ifndef PRODUCT
-bool CMBitMapRO::covers(MemRegion heap_rs) const {
- // assert(_bm.map() == _virtual_space.low(), "map inconsistency");
- assert(((size_t)_bm.size() * ((size_t)1 << _shifter)) == _bmWordSize,
- "size inconsistency");
- return _bmStartWord == (HeapWord*)(heap_rs.start()) &&
- _bmWordSize == heap_rs.word_size();
-}
-#endif
-
-void CMBitMapRO::print_on_error(outputStream* st, const char* prefix) const {
- _bm.print_on_error(st, prefix);
-}
-
-size_t CMBitMap::compute_size(size_t heap_size) {
- return ReservedSpace::allocation_align_size_up(heap_size / mark_distance());
-}
-
-size_t CMBitMap::mark_distance() {
- return MinObjAlignmentInBytes * BitsPerByte;
-}
-
-void CMBitMap::initialize(MemRegion heap, G1RegionToSpaceMapper* storage) {
- _bmStartWord = heap.start();
- _bmWordSize = heap.word_size();
-
- _bm.set_map((BitMap::bm_word_t*) storage->reserved().start());
- _bm.set_size(_bmWordSize >> _shifter);
-
- storage->set_mapping_changed_listener(&_listener);
-}
-
-void CMBitMapMappingChangedListener::on_commit(uint start_region, size_t num_regions, bool zero_filled) {
- if (zero_filled) {
- return;
- }
- // We need to clear the bitmap on commit, removing any existing information.
- MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_region), num_regions * HeapRegion::GrainWords);
- _bm->clearRange(mr);
-}
-
-// Closure used for clearing the given mark bitmap.
-class ClearBitmapHRClosure : public HeapRegionClosure {
- private:
- ConcurrentMark* _cm;
- CMBitMap* _bitmap;
- bool _may_yield; // The closure may yield during iteration. If yielded, abort the iteration.
- public:
- ClearBitmapHRClosure(ConcurrentMark* cm, CMBitMap* bitmap, bool may_yield) : HeapRegionClosure(), _cm(cm), _bitmap(bitmap), _may_yield(may_yield) {
- assert(!may_yield || cm != NULL, "CM must be non-NULL if this closure is expected to yield.");
- }
-
- virtual bool doHeapRegion(HeapRegion* r) {
- size_t const chunk_size_in_words = M / HeapWordSize;
-
- HeapWord* cur = r->bottom();
- HeapWord* const end = r->end();
-
- while (cur < end) {
- MemRegion mr(cur, MIN2(cur + chunk_size_in_words, end));
- _bitmap->clearRange(mr);
-
- cur += chunk_size_in_words;
-
- // Abort iteration if after yielding the marking has been aborted.
- if (_may_yield && _cm->do_yield_check() && _cm->has_aborted()) {
- return true;
- }
- // Repeat the asserts from before the start of the closure. We will do them
- // as asserts here to minimize their overhead on the product. However, we
- // will have them as guarantees at the beginning / end of the bitmap
- // clearing to get some checking in the product.
- assert(!_may_yield || _cm->cmThread()->during_cycle(), "invariant");
- assert(!_may_yield || !G1CollectedHeap::heap()->collector_state()->mark_in_progress(), "invariant");
- }
-
- return false;
- }
-};
-
-class ParClearNextMarkBitmapTask : public AbstractGangTask {
- ClearBitmapHRClosure* _cl;
- HeapRegionClaimer _hrclaimer;
- bool _suspendible; // If the task is suspendible, workers must join the STS.
-
-public:
- ParClearNextMarkBitmapTask(ClearBitmapHRClosure *cl, uint n_workers, bool suspendible) :
- _cl(cl), _suspendible(suspendible), AbstractGangTask("Parallel Clear Bitmap Task"), _hrclaimer(n_workers) {}
-
- void work(uint worker_id) {
- SuspendibleThreadSetJoiner sts_join(_suspendible);
- G1CollectedHeap::heap()->heap_region_par_iterate(_cl, worker_id, &_hrclaimer, true);
- }
-};
-
-void CMBitMap::clearAll() {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- ClearBitmapHRClosure cl(NULL, this, false /* may_yield */);
- uint n_workers = g1h->workers()->active_workers();
- ParClearNextMarkBitmapTask task(&cl, n_workers, false);
- g1h->workers()->run_task(&task);
- guarantee(cl.complete(), "Must have completed iteration.");
- return;
-}
-
-void CMBitMap::clearRange(MemRegion mr) {
- mr.intersection(MemRegion(_bmStartWord, _bmWordSize));
- assert(!mr.is_empty(), "unexpected empty region");
- // convert address range into offset range
- _bm.at_put_range(heapWordToOffset(mr.start()),
- heapWordToOffset(mr.end()), false);
-}
-
-CMMarkStack::CMMarkStack(ConcurrentMark* cm) :
- _base(NULL), _cm(cm)
-{}
-
-bool CMMarkStack::allocate(size_t capacity) {
- // allocate a stack of the requisite depth
- ReservedSpace rs(ReservedSpace::allocation_align_size_up(capacity * sizeof(oop)));
- if (!rs.is_reserved()) {
- warning("ConcurrentMark MarkStack allocation failure");
- return false;
- }
- MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
- if (!_virtual_space.initialize(rs, rs.size())) {
- warning("ConcurrentMark MarkStack backing store failure");
- // Release the virtual memory reserved for the marking stack
- rs.release();
- return false;
- }
- assert(_virtual_space.committed_size() == rs.size(),
- "Didn't reserve backing store for all of ConcurrentMark stack?");
- _base = (oop*) _virtual_space.low();
- setEmpty();
- _capacity = (jint) capacity;
- _saved_index = -1;
- _should_expand = false;
- return true;
-}
-
-void CMMarkStack::expand() {
- // Called, during remark, if we've overflown the marking stack during marking.
- assert(isEmpty(), "stack should been emptied while handling overflow");
- assert(_capacity <= (jint) MarkStackSizeMax, "stack bigger than permitted");
- // Clear expansion flag
- _should_expand = false;
- if (_capacity == (jint) MarkStackSizeMax) {
- log_trace(gc)("(benign) Can't expand marking stack capacity, at max size limit");
- return;
- }
- // Double capacity if possible
- jint new_capacity = MIN2(_capacity*2, (jint) MarkStackSizeMax);
- // Do not give up existing stack until we have managed to
- // get the double capacity that we desired.
- ReservedSpace rs(ReservedSpace::allocation_align_size_up(new_capacity *
- sizeof(oop)));
- if (rs.is_reserved()) {
- // Release the backing store associated with old stack
- _virtual_space.release();
- // Reinitialize virtual space for new stack
- if (!_virtual_space.initialize(rs, rs.size())) {
- fatal("Not enough swap for expanded marking stack capacity");
- }
- _base = (oop*)(_virtual_space.low());
- _index = 0;
- _capacity = new_capacity;
- } else {
- // Failed to double capacity, continue;
- log_trace(gc)("(benign) Failed to expand marking stack capacity from " SIZE_FORMAT "K to " SIZE_FORMAT "K",
- _capacity / K, new_capacity / K);
- }
-}
-
-void CMMarkStack::set_should_expand() {
- // If we're resetting the marking state because of an
- // marking stack overflow, record that we should, if
- // possible, expand the stack.
- _should_expand = _cm->has_overflown();
-}
-
-CMMarkStack::~CMMarkStack() {
- if (_base != NULL) {
- _base = NULL;
- _virtual_space.release();
- }
-}
-
-void CMMarkStack::par_push_arr(oop* ptr_arr, int n) {
- MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
- jint start = _index;
- jint next_index = start + n;
- if (next_index > _capacity) {
- _overflow = true;
- return;
- }
- // Otherwise.
- _index = next_index;
- for (int i = 0; i < n; i++) {
- int ind = start + i;
- assert(ind < _capacity, "By overflow test above.");
- _base[ind] = ptr_arr[i];
- }
-}
-
-bool CMMarkStack::par_pop_arr(oop* ptr_arr, int max, int* n) {
- MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
- jint index = _index;
- if (index == 0) {
- *n = 0;
- return false;
- } else {
- int k = MIN2(max, index);
- jint new_ind = index - k;
- for (int j = 0; j < k; j++) {
- ptr_arr[j] = _base[new_ind + j];
- }
- _index = new_ind;
- *n = k;
- return true;
- }
-}
-
-void CMMarkStack::note_start_of_gc() {
- assert(_saved_index == -1,
- "note_start_of_gc()/end_of_gc() bracketed incorrectly");
- _saved_index = _index;
-}
-
-void CMMarkStack::note_end_of_gc() {
- // This is intentionally a guarantee, instead of an assert. If we
- // accidentally add something to the mark stack during GC, it
- // will be a correctness issue so it's better if we crash. we'll
- // only check this once per GC anyway, so it won't be a performance
- // issue in any way.
- guarantee(_saved_index == _index,
- "saved index: %d index: %d", _saved_index, _index);
- _saved_index = -1;
-}
-
-CMRootRegions::CMRootRegions() :
- _young_list(NULL), _cm(NULL), _scan_in_progress(false),
- _should_abort(false), _next_survivor(NULL) { }
-
-void CMRootRegions::init(G1CollectedHeap* g1h, ConcurrentMark* cm) {
- _young_list = g1h->young_list();
- _cm = cm;
-}
-
-void CMRootRegions::prepare_for_scan() {
- assert(!scan_in_progress(), "pre-condition");
-
- // Currently, only survivors can be root regions.
- assert(_next_survivor == NULL, "pre-condition");
- _next_survivor = _young_list->first_survivor_region();
- _scan_in_progress = (_next_survivor != NULL);
- _should_abort = false;
-}
-
-HeapRegion* CMRootRegions::claim_next() {
- if (_should_abort) {
- // If someone has set the should_abort flag, we return NULL to
- // force the caller to bail out of their loop.
- return NULL;
- }
-
- // Currently, only survivors can be root regions.
- HeapRegion* res = _next_survivor;
- if (res != NULL) {
- MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
- // Read it again in case it changed while we were waiting for the lock.
- res = _next_survivor;
- if (res != NULL) {
- if (res == _young_list->last_survivor_region()) {
- // We just claimed the last survivor so store NULL to indicate
- // that we're done.
- _next_survivor = NULL;
- } else {
- _next_survivor = res->get_next_young_region();
- }
- } else {
- // Someone else claimed the last survivor while we were trying
- // to take the lock so nothing else to do.
- }
- }
- assert(res == NULL || res->is_survivor(), "post-condition");
-
- return res;
-}
-
-void CMRootRegions::scan_finished() {
- assert(scan_in_progress(), "pre-condition");
-
- // Currently, only survivors can be root regions.
- if (!_should_abort) {
- assert(_next_survivor == NULL, "we should have claimed all survivors");
- }
- _next_survivor = NULL;
-
- {
- MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
- _scan_in_progress = false;
- RootRegionScan_lock->notify_all();
- }
-}
-
-bool CMRootRegions::wait_until_scan_finished() {
- if (!scan_in_progress()) return false;
-
- {
- MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
- while (scan_in_progress()) {
- RootRegionScan_lock->wait(Mutex::_no_safepoint_check_flag);
- }
- }
- return true;
-}
-
-uint ConcurrentMark::scale_parallel_threads(uint n_par_threads) {
- return MAX2((n_par_threads + 2) / 4, 1U);
-}
-
-ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev_bitmap_storage, G1RegionToSpaceMapper* next_bitmap_storage) :
- _g1h(g1h),
- _markBitMap1(),
- _markBitMap2(),
- _parallel_marking_threads(0),
- _max_parallel_marking_threads(0),
- _sleep_factor(0.0),
- _marking_task_overhead(1.0),
- _cleanup_list("Cleanup List"),
- _region_bm((BitMap::idx_t)(g1h->max_regions()), false /* in_resource_area*/),
- _card_bm((g1h->reserved_region().byte_size() + CardTableModRefBS::card_size - 1) >>
- CardTableModRefBS::card_shift,
- false /* in_resource_area*/),
-
- _prevMarkBitMap(&_markBitMap1),
- _nextMarkBitMap(&_markBitMap2),
-
- _markStack(this),
- // _finger set in set_non_marking_state
-
- _max_worker_id(ParallelGCThreads),
- // _active_tasks set in set_non_marking_state
- // _tasks set inside the constructor
- _task_queues(new CMTaskQueueSet((int) _max_worker_id)),
- _terminator(ParallelTaskTerminator((int) _max_worker_id, _task_queues)),
-
- _has_overflown(false),
- _concurrent(false),
- _has_aborted(false),
- _restart_for_overflow(false),
- _concurrent_marking_in_progress(false),
- _concurrent_phase_started(false),
-
- // _verbose_level set below
-
- _init_times(),
- _remark_times(), _remark_mark_times(), _remark_weak_ref_times(),
- _cleanup_times(),
- _total_counting_time(0.0),
- _total_rs_scrub_time(0.0),
-
- _parallel_workers(NULL),
-
- _count_card_bitmaps(NULL),
- _count_marked_bytes(NULL),
- _completed_initialization(false) {
-
- _markBitMap1.initialize(g1h->reserved_region(), prev_bitmap_storage);
- _markBitMap2.initialize(g1h->reserved_region(), next_bitmap_storage);
-
- // Create & start a ConcurrentMark thread.
- _cmThread = new ConcurrentMarkThread(this);
- assert(cmThread() != NULL, "CM Thread should have been created");
- assert(cmThread()->cm() != NULL, "CM Thread should refer to this cm");
- if (_cmThread->osthread() == NULL) {
- vm_shutdown_during_initialization("Could not create ConcurrentMarkThread");
- }
-
- assert(CGC_lock != NULL, "Where's the CGC_lock?");
- assert(_markBitMap1.covers(g1h->reserved_region()), "_markBitMap1 inconsistency");
- assert(_markBitMap2.covers(g1h->reserved_region()), "_markBitMap2 inconsistency");
-
- SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set();
- satb_qs.set_buffer_size(G1SATBBufferSize);
-
- _root_regions.init(_g1h, this);
-
- if (ConcGCThreads > ParallelGCThreads) {
- warning("Can't have more ConcGCThreads (%u) "
- "than ParallelGCThreads (%u).",
- ConcGCThreads, ParallelGCThreads);
- return;
- }
- if (!FLAG_IS_DEFAULT(ConcGCThreads) && ConcGCThreads > 0) {
- // Note: ConcGCThreads has precedence over G1MarkingOverheadPercent
- // if both are set
- _sleep_factor = 0.0;
- _marking_task_overhead = 1.0;
- } else if (G1MarkingOverheadPercent > 0) {
- // We will calculate the number of parallel marking threads based
- // on a target overhead with respect to the soft real-time goal
- double marking_overhead = (double) G1MarkingOverheadPercent / 100.0;
- double overall_cm_overhead =
- (double) MaxGCPauseMillis * marking_overhead /
- (double) GCPauseIntervalMillis;
- double cpu_ratio = 1.0 / (double) os::processor_count();
- double marking_thread_num = ceil(overall_cm_overhead / cpu_ratio);
- double marking_task_overhead =
- overall_cm_overhead / marking_thread_num *
- (double) os::processor_count();
- double sleep_factor =
- (1.0 - marking_task_overhead) / marking_task_overhead;
-
- FLAG_SET_ERGO(uint, ConcGCThreads, (uint) marking_thread_num);
- _sleep_factor = sleep_factor;
- _marking_task_overhead = marking_task_overhead;
- } else {
- // Calculate the number of parallel marking threads by scaling
- // the number of parallel GC threads.
- uint marking_thread_num = scale_parallel_threads(ParallelGCThreads);
- FLAG_SET_ERGO(uint, ConcGCThreads, marking_thread_num);
- _sleep_factor = 0.0;
- _marking_task_overhead = 1.0;
- }
-
- assert(ConcGCThreads > 0, "Should have been set");
- _parallel_marking_threads = ConcGCThreads;
- _max_parallel_marking_threads = _parallel_marking_threads;
-
- _parallel_workers = new WorkGang("G1 Marker",
- _max_parallel_marking_threads, false, true);
- if (_parallel_workers == NULL) {
- vm_exit_during_initialization("Failed necessary allocation.");
- } else {
- _parallel_workers->initialize_workers();
- }
-
- if (FLAG_IS_DEFAULT(MarkStackSize)) {
- size_t mark_stack_size =
- MIN2(MarkStackSizeMax,
- MAX2(MarkStackSize, (size_t) (parallel_marking_threads() * TASKQUEUE_SIZE)));
- // Verify that the calculated value for MarkStackSize is in range.
- // It would be nice to use the private utility routine from Arguments.
- if (!(mark_stack_size >= 1 && mark_stack_size <= MarkStackSizeMax)) {
- warning("Invalid value calculated for MarkStackSize (" SIZE_FORMAT "): "
- "must be between 1 and " SIZE_FORMAT,
- mark_stack_size, MarkStackSizeMax);
- return;
- }
- FLAG_SET_ERGO(size_t, MarkStackSize, mark_stack_size);
- } else {
- // Verify MarkStackSize is in range.
- if (FLAG_IS_CMDLINE(MarkStackSize)) {
- if (FLAG_IS_DEFAULT(MarkStackSizeMax)) {
- if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
- warning("Invalid value specified for MarkStackSize (" SIZE_FORMAT "): "
- "must be between 1 and " SIZE_FORMAT,
- MarkStackSize, MarkStackSizeMax);
- return;
- }
- } else if (FLAG_IS_CMDLINE(MarkStackSizeMax)) {
- if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
- warning("Invalid value specified for MarkStackSize (" SIZE_FORMAT ")"
- " or for MarkStackSizeMax (" SIZE_FORMAT ")",
- MarkStackSize, MarkStackSizeMax);
- return;
- }
- }
- }
- }
-
- if (!_markStack.allocate(MarkStackSize)) {
- warning("Failed to allocate CM marking stack");
- return;
- }
-
- _tasks = NEW_C_HEAP_ARRAY(CMTask*, _max_worker_id, mtGC);
- _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC);
-
- _count_card_bitmaps = NEW_C_HEAP_ARRAY(BitMap, _max_worker_id, mtGC);
- _count_marked_bytes = NEW_C_HEAP_ARRAY(size_t*, _max_worker_id, mtGC);
-
- BitMap::idx_t card_bm_size = _card_bm.size();
-
- // so that the assertion in MarkingTaskQueue::task_queue doesn't fail
- _active_tasks = _max_worker_id;
-
- uint max_regions = _g1h->max_regions();
- for (uint i = 0; i < _max_worker_id; ++i) {
- CMTaskQueue* task_queue = new CMTaskQueue();
- task_queue->initialize();
- _task_queues->register_queue(i, task_queue);
-
- _count_card_bitmaps[i] = BitMap(card_bm_size, false);
- _count_marked_bytes[i] = NEW_C_HEAP_ARRAY(size_t, max_regions, mtGC);
-
- _tasks[i] = new CMTask(i, this,
- _count_marked_bytes[i],
- &_count_card_bitmaps[i],
- task_queue, _task_queues);
-
- _accum_task_vtime[i] = 0.0;
- }
-
- // Calculate the card number for the bottom of the heap. Used
- // in biasing indexes into the accounting card bitmaps.
- _heap_bottom_card_num =
- intptr_t(uintptr_t(_g1h->reserved_region().start()) >>
- CardTableModRefBS::card_shift);
-
- // Clear all the liveness counting data
- clear_all_count_data();
-
- // so that the call below can read a sensible value
- _heap_start = g1h->reserved_region().start();
- set_non_marking_state();
- _completed_initialization = true;
-}
-
-void ConcurrentMark::reset() {
- // Starting values for these two. This should be called in a STW
- // phase.
- MemRegion reserved = _g1h->g1_reserved();
- _heap_start = reserved.start();
- _heap_end = reserved.end();
-
- // Separated the asserts so that we know which one fires.
- assert(_heap_start != NULL, "heap bounds should look ok");
- assert(_heap_end != NULL, "heap bounds should look ok");
- assert(_heap_start < _heap_end, "heap bounds should look ok");
-
- // Reset all the marking data structures and any necessary flags
- reset_marking_state();
-
- // We do reset all of them, since different phases will use
- // different number of active threads. So, it's easiest to have all
- // of them ready.
- for (uint i = 0; i < _max_worker_id; ++i) {
- _tasks[i]->reset(_nextMarkBitMap);
- }
-
- // we need this to make sure that the flag is on during the evac
- // pause with initial mark piggy-backed
- set_concurrent_marking_in_progress();
-}
-
-
-void ConcurrentMark::reset_marking_state(bool clear_overflow) {
- _markStack.set_should_expand();
- _markStack.setEmpty(); // Also clears the _markStack overflow flag
- if (clear_overflow) {
- clear_has_overflown();
- } else {
- assert(has_overflown(), "pre-condition");
- }
- _finger = _heap_start;
-
- for (uint i = 0; i < _max_worker_id; ++i) {
- CMTaskQueue* queue = _task_queues->queue(i);
- queue->set_empty();
- }
-}
-
-void ConcurrentMark::set_concurrency(uint active_tasks) {
- assert(active_tasks <= _max_worker_id, "we should not have more");
-
- _active_tasks = active_tasks;
- // Need to update the three data structures below according to the
- // number of active threads for this phase.
- _terminator = ParallelTaskTerminator((int) active_tasks, _task_queues);
- _first_overflow_barrier_sync.set_n_workers((int) active_tasks);
- _second_overflow_barrier_sync.set_n_workers((int) active_tasks);
-}
-
-void ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurrent) {
- set_concurrency(active_tasks);
-
- _concurrent = concurrent;
- // We propagate this to all tasks, not just the active ones.
- for (uint i = 0; i < _max_worker_id; ++i)
- _tasks[i]->set_concurrent(concurrent);
-
- if (concurrent) {
- set_concurrent_marking_in_progress();
- } else {
- // We currently assume that the concurrent flag has been set to
- // false before we start remark. At this point we should also be
- // in a STW phase.
- assert(!concurrent_marking_in_progress(), "invariant");
- assert(out_of_regions(),
- "only way to get here: _finger: " PTR_FORMAT ", _heap_end: " PTR_FORMAT,
- p2i(_finger), p2i(_heap_end));
- }
-}
-
-void ConcurrentMark::set_non_marking_state() {
- // We set the global marking state to some default values when we're
- // not doing marking.
- reset_marking_state();
- _active_tasks = 0;
- clear_concurrent_marking_in_progress();
-}
-
-ConcurrentMark::~ConcurrentMark() {
- // The ConcurrentMark instance is never freed.
- ShouldNotReachHere();
-}
-
-void ConcurrentMark::clearNextBitmap() {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
-
- // Make sure that the concurrent mark thread looks to still be in
- // the current cycle.
- guarantee(cmThread()->during_cycle(), "invariant");
-
- // We are finishing up the current cycle by clearing the next
- // marking bitmap and getting it ready for the next cycle. During
- // this time no other cycle can start. So, let's make sure that this
- // is the case.
- guarantee(!g1h->collector_state()->mark_in_progress(), "invariant");
-
- ClearBitmapHRClosure cl(this, _nextMarkBitMap, true /* may_yield */);
- ParClearNextMarkBitmapTask task(&cl, parallel_marking_threads(), true);
- _parallel_workers->run_task(&task);
-
- // Clear the liveness counting data. If the marking has been aborted, the abort()
- // call already did that.
- if (cl.complete()) {
- clear_all_count_data();
- }
-
- // Repeat the asserts from above.
- guarantee(cmThread()->during_cycle(), "invariant");
- guarantee(!g1h->collector_state()->mark_in_progress(), "invariant");
-}
-
-class CheckBitmapClearHRClosure : public HeapRegionClosure {
- CMBitMap* _bitmap;
- bool _error;
- public:
- CheckBitmapClearHRClosure(CMBitMap* bitmap) : _bitmap(bitmap) {
- }
-
- virtual bool doHeapRegion(HeapRegion* r) {
- // This closure can be called concurrently to the mutator, so we must make sure
- // that the result of the getNextMarkedWordAddress() call is compared to the
- // value passed to it as limit to detect any found bits.
- // end never changes in G1.
- HeapWord* end = r->end();
- return _bitmap->getNextMarkedWordAddress(r->bottom(), end) != end;
- }
-};
-
-bool ConcurrentMark::nextMarkBitmapIsClear() {
- CheckBitmapClearHRClosure cl(_nextMarkBitMap);
- _g1h->heap_region_iterate(&cl);
- return cl.complete();
-}
-
-class NoteStartOfMarkHRClosure: public HeapRegionClosure {
-public:
- bool doHeapRegion(HeapRegion* r) {
- r->note_start_of_marking();
- return false;
- }
-};
-
-void ConcurrentMark::checkpointRootsInitialPre() {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- G1CollectorPolicy* g1p = g1h->g1_policy();
-
- _has_aborted = false;
-
- // Initialize marking structures. This has to be done in a STW phase.
- reset();
-
- // For each region note start of marking.
- NoteStartOfMarkHRClosure startcl;
- g1h->heap_region_iterate(&startcl);
-}
-
-
-void ConcurrentMark::checkpointRootsInitialPost() {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
-
- // Start Concurrent Marking weak-reference discovery.
- ReferenceProcessor* rp = g1h->ref_processor_cm();
- // enable ("weak") refs discovery
- rp->enable_discovery();
- rp->setup_policy(false); // snapshot the soft ref policy to be used in this cycle
-
- SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
- // This is the start of the marking cycle, we're expected all
- // threads to have SATB queues with active set to false.
- satb_mq_set.set_active_all_threads(true, /* new active value */
- false /* expected_active */);
-
- _root_regions.prepare_for_scan();
-
- // update_g1_committed() will be called at the end of an evac pause
- // when marking is on. So, it's also called at the end of the
- // initial-mark pause to update the heap end, if the heap expands
- // during it. No need to call it here.
-}
-
-/*
- * Notice that in the next two methods, we actually leave the STS
- * during the barrier sync and join it immediately afterwards. If we
- * do not do this, the following deadlock can occur: one thread could
- * be in the barrier sync code, waiting for the other thread to also
- * sync up, whereas another one could be trying to yield, while also
- * waiting for the other threads to sync up too.
- *
- * Note, however, that this code is also used during remark and in
- * this case we should not attempt to leave / enter the STS, otherwise
- * we'll either hit an assert (debug / fastdebug) or deadlock
- * (product). So we should only leave / enter the STS if we are
- * operating concurrently.
- *
- * Because the thread that does the sync barrier has left the STS, it
- * is possible to be suspended for a Full GC or an evacuation pause
- * could occur. This is actually safe, since the entering the sync
- * barrier is one of the last things do_marking_step() does, and it
- * doesn't manipulate any data structures afterwards.
- */
-
-void ConcurrentMark::enter_first_sync_barrier(uint worker_id) {
- bool barrier_aborted;
- {
- SuspendibleThreadSetLeaver sts_leave(concurrent());
- barrier_aborted = !_first_overflow_barrier_sync.enter();
- }
-
- // at this point everyone should have synced up and not be doing any
- // more work
-
- if (barrier_aborted) {
- // If the barrier aborted we ignore the overflow condition and
- // just abort the whole marking phase as quickly as possible.
- return;
- }
-
- // If we're executing the concurrent phase of marking, reset the marking
- // state; otherwise the marking state is reset after reference processing,
- // during the remark pause.
- // If we reset here as a result of an overflow during the remark we will
- // see assertion failures from any subsequent set_concurrency_and_phase()
- // calls.
- if (concurrent()) {
- // let the task associated with with worker 0 do this
- if (worker_id == 0) {
- // task 0 is responsible for clearing the global data structures
- // We should be here because of an overflow. During STW we should
- // not clear the overflow flag since we rely on it being true when
- // we exit this method to abort the pause and restart concurrent
- // marking.
- reset_marking_state(true /* clear_overflow */);
-
- log_info(gc)("Concurrent Mark reset for overflow");
- }
- }
-
- // after this, each task should reset its own data structures then
- // then go into the second barrier
-}
-
-void ConcurrentMark::enter_second_sync_barrier(uint worker_id) {
- SuspendibleThreadSetLeaver sts_leave(concurrent());
- _second_overflow_barrier_sync.enter();
-
- // at this point everything should be re-initialized and ready to go
-}
-
-class CMConcurrentMarkingTask: public AbstractGangTask {
-private:
- ConcurrentMark* _cm;
- ConcurrentMarkThread* _cmt;
-
-public:
- void work(uint worker_id) {
- assert(Thread::current()->is_ConcurrentGC_thread(),
- "this should only be done by a conc GC thread");
- ResourceMark rm;
-
- double start_vtime = os::elapsedVTime();
-
- {
- SuspendibleThreadSetJoiner sts_join;
-
- assert(worker_id < _cm->active_tasks(), "invariant");
- CMTask* the_task = _cm->task(worker_id);
- the_task->record_start_time();
- if (!_cm->has_aborted()) {
- do {
- double start_vtime_sec = os::elapsedVTime();
- double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
-
- the_task->do_marking_step(mark_step_duration_ms,
- true /* do_termination */,
- false /* is_serial*/);
-
- double end_vtime_sec = os::elapsedVTime();
- double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec;
- _cm->clear_has_overflown();
-
- _cm->do_yield_check(worker_id);
-
- jlong sleep_time_ms;
- if (!_cm->has_aborted() && the_task->has_aborted()) {
- sleep_time_ms =
- (jlong) (elapsed_vtime_sec * _cm->sleep_factor() * 1000.0);
- {
- SuspendibleThreadSetLeaver sts_leave;
- os::sleep(Thread::current(), sleep_time_ms, false);
- }
- }
- } while (!_cm->has_aborted() && the_task->has_aborted());
- }
- the_task->record_end_time();
- guarantee(!the_task->has_aborted() || _cm->has_aborted(), "invariant");
- }
-
- double end_vtime = os::elapsedVTime();
- _cm->update_accum_task_vtime(worker_id, end_vtime - start_vtime);
- }
-
- CMConcurrentMarkingTask(ConcurrentMark* cm,
- ConcurrentMarkThread* cmt) :
- AbstractGangTask("Concurrent Mark"), _cm(cm), _cmt(cmt) { }
-
- ~CMConcurrentMarkingTask() { }
-};
-
-// Calculates the number of active workers for a concurrent
-// phase.
-uint ConcurrentMark::calc_parallel_marking_threads() {
- uint n_conc_workers = 0;
- if (!UseDynamicNumberOfGCThreads ||
- (!FLAG_IS_DEFAULT(ConcGCThreads) &&
- !ForceDynamicNumberOfGCThreads)) {
- n_conc_workers = max_parallel_marking_threads();
- } else {
- n_conc_workers =
- AdaptiveSizePolicy::calc_default_active_workers(
- max_parallel_marking_threads(),
- 1, /* Minimum workers */
- parallel_marking_threads(),
- Threads::number_of_non_daemon_threads());
- // Don't scale down "n_conc_workers" by scale_parallel_threads() because
- // that scaling has already gone into "_max_parallel_marking_threads".
- }
- assert(n_conc_workers > 0, "Always need at least 1");
- return n_conc_workers;
-}
-
-void ConcurrentMark::scanRootRegion(HeapRegion* hr, uint worker_id) {
- // Currently, only survivors can be root regions.
- assert(hr->next_top_at_mark_start() == hr->bottom(), "invariant");
- G1RootRegionScanClosure cl(_g1h, this, worker_id);
-
- const uintx interval = PrefetchScanIntervalInBytes;
- HeapWord* curr = hr->bottom();
- const HeapWord* end = hr->top();
- while (curr < end) {
- Prefetch::read(curr, interval);
- oop obj = oop(curr);
- int size = obj->oop_iterate_size(&cl);
- assert(size == obj->size(), "sanity");
- curr += size;
- }
-}
-
-class CMRootRegionScanTask : public AbstractGangTask {
-private:
- ConcurrentMark* _cm;
-
-public:
- CMRootRegionScanTask(ConcurrentMark* cm) :
- AbstractGangTask("Root Region Scan"), _cm(cm) { }
-
- void work(uint worker_id) {
- assert(Thread::current()->is_ConcurrentGC_thread(),
- "this should only be done by a conc GC thread");
-
- CMRootRegions* root_regions = _cm->root_regions();
- HeapRegion* hr = root_regions->claim_next();
- while (hr != NULL) {
- _cm->scanRootRegion(hr, worker_id);
- hr = root_regions->claim_next();
- }
- }
-};
-
-void ConcurrentMark::scanRootRegions() {
- // Start of concurrent marking.
- ClassLoaderDataGraph::clear_claimed_marks();
-
- // scan_in_progress() will have been set to true only if there was
- // at least one root region to scan. So, if it's false, we
- // should not attempt to do any further work.
- if (root_regions()->scan_in_progress()) {
- GCTraceConcTime(Info, gc) tt("Concurrent Root Region Scan");
-
- _parallel_marking_threads = calc_parallel_marking_threads();
- assert(parallel_marking_threads() <= max_parallel_marking_threads(),
- "Maximum number of marking threads exceeded");
- uint active_workers = MAX2(1U, parallel_marking_threads());
-
- CMRootRegionScanTask task(this);
- _parallel_workers->set_active_workers(active_workers);
- _parallel_workers->run_task(&task);
-
- // It's possible that has_aborted() is true here without actually
- // aborting the survivor scan earlier. This is OK as it's
- // mainly used for sanity checking.
- root_regions()->scan_finished();
- }
-}
-
-void ConcurrentMark::register_concurrent_phase_start(const char* title) {
- assert(!_concurrent_phase_started, "Sanity");
- _concurrent_phase_started = true;
- _g1h->gc_timer_cm()->register_gc_concurrent_start(title);
-}
-
-void ConcurrentMark::register_concurrent_phase_end() {
- if (_concurrent_phase_started) {
- _concurrent_phase_started = false;
- _g1h->gc_timer_cm()->register_gc_concurrent_end();
- }
-}
-
-void ConcurrentMark::markFromRoots() {
- // we might be tempted to assert that:
- // assert(asynch == !SafepointSynchronize::is_at_safepoint(),
- // "inconsistent argument?");
- // However that wouldn't be right, because it's possible that
- // a safepoint is indeed in progress as a younger generation
- // stop-the-world GC happens even as we mark in this generation.
-
- _restart_for_overflow = false;
-
- // _g1h has _n_par_threads
- _parallel_marking_threads = calc_parallel_marking_threads();
- assert(parallel_marking_threads() <= max_parallel_marking_threads(),
- "Maximum number of marking threads exceeded");
-
- uint active_workers = MAX2(1U, parallel_marking_threads());
- assert(active_workers > 0, "Should have been set");
-
- // Parallel task terminator is set in "set_concurrency_and_phase()"
- set_concurrency_and_phase(active_workers, true /* concurrent */);
-
- CMConcurrentMarkingTask markingTask(this, cmThread());
- _parallel_workers->set_active_workers(active_workers);
- _parallel_workers->run_task(&markingTask);
- print_stats();
-}
-
-void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
- // world is stopped at this checkpoint
- assert(SafepointSynchronize::is_at_safepoint(),
- "world should be stopped");
-
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
-
- // If a full collection has happened, we shouldn't do this.
- if (has_aborted()) {
- g1h->collector_state()->set_mark_in_progress(false); // So bitmap clearing isn't confused
- return;
- }
-
- SvcGCMarker sgcm(SvcGCMarker::OTHER);
-
- if (VerifyDuringGC) {
- HandleMark hm; // handle scope
- g1h->prepare_for_verify();
- Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (before)");
- }
- g1h->check_bitmaps("Remark Start");
-
- G1CollectorPolicy* g1p = g1h->g1_policy();
- g1p->record_concurrent_mark_remark_start();
-
- double start = os::elapsedTime();
-
- checkpointRootsFinalWork();
-
- double mark_work_end = os::elapsedTime();
-
- weakRefsWork(clear_all_soft_refs);
-
- if (has_overflown()) {
- // Oops. We overflowed. Restart concurrent marking.
- _restart_for_overflow = true;
- log_develop_trace(gc)("Remark led to restart for overflow.");
-
- // Verify the heap w.r.t. the previous marking bitmap.
- if (VerifyDuringGC) {
- HandleMark hm; // handle scope
- g1h->prepare_for_verify();
- Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (overflow)");
- }
-
- // Clear the marking state because we will be restarting
- // marking due to overflowing the global mark stack.
- reset_marking_state();
- } else {
- {
- GCTraceTime(Debug, gc) trace("GC Aggregate Data", g1h->gc_timer_cm());
-
- // Aggregate the per-task counting data that we have accumulated
- // while marking.
- aggregate_count_data();
- }
-
- SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
- // We're done with marking.
- // This is the end of the marking cycle, we're expected all
- // threads to have SATB queues with active set to true.
- satb_mq_set.set_active_all_threads(false, /* new active value */
- true /* expected_active */);
-
- if (VerifyDuringGC) {
- HandleMark hm; // handle scope
- g1h->prepare_for_verify();
- Universe::verify(VerifyOption_G1UseNextMarking, "During GC (after)");
- }
- g1h->check_bitmaps("Remark End");
- assert(!restart_for_overflow(), "sanity");
- // Completely reset the marking state since marking completed
- set_non_marking_state();
- }
-
- // Expand the marking stack, if we have to and if we can.
- if (_markStack.should_expand()) {
- _markStack.expand();
- }
-
- // Statistics
- double now = os::elapsedTime();
- _remark_mark_times.add((mark_work_end - start) * 1000.0);
- _remark_weak_ref_times.add((now - mark_work_end) * 1000.0);
- _remark_times.add((now - start) * 1000.0);
-
- g1p->record_concurrent_mark_remark_end();
-
- G1CMIsAliveClosure is_alive(g1h);
- g1h->gc_tracer_cm()->report_object_count_after_gc(&is_alive);
-}
-
-// Base class of the closures that finalize and verify the
-// liveness counting data.
-class CMCountDataClosureBase: public HeapRegionClosure {
-protected:
- G1CollectedHeap* _g1h;
- ConcurrentMark* _cm;
- CardTableModRefBS* _ct_bs;
-
- BitMap* _region_bm;
- BitMap* _card_bm;
-
- // Takes a region that's not empty (i.e., it has at least one
- // live object in it and sets its corresponding bit on the region
- // bitmap to 1.
- void set_bit_for_region(HeapRegion* hr) {
- BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
- _region_bm->par_at_put(index, true);
- }
-
-public:
- CMCountDataClosureBase(G1CollectedHeap* g1h,
- BitMap* region_bm, BitMap* card_bm):
- _g1h(g1h), _cm(g1h->concurrent_mark()),
- _ct_bs(barrier_set_cast<CardTableModRefBS>(g1h->barrier_set())),
- _region_bm(region_bm), _card_bm(card_bm) { }
-};
-
-// Closure that calculates the # live objects per region. Used
-// for verification purposes during the cleanup pause.
-class CalcLiveObjectsClosure: public CMCountDataClosureBase {
- CMBitMapRO* _bm;
- size_t _region_marked_bytes;
-
-public:
- CalcLiveObjectsClosure(CMBitMapRO *bm, G1CollectedHeap* g1h,
- BitMap* region_bm, BitMap* card_bm) :
- CMCountDataClosureBase(g1h, region_bm, card_bm),
- _bm(bm), _region_marked_bytes(0) { }
-
- bool doHeapRegion(HeapRegion* hr) {
- HeapWord* ntams = hr->next_top_at_mark_start();
- HeapWord* start = hr->bottom();
-
- assert(start <= hr->end() && start <= ntams && ntams <= hr->end(),
- "Preconditions not met - "
- "start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT,
- p2i(start), p2i(ntams), p2i(hr->end()));
-
- // Find the first marked object at or after "start".
- start = _bm->getNextMarkedWordAddress(start, ntams);
-
- size_t marked_bytes = 0;
-
- while (start < ntams) {
- oop obj = oop(start);
- int obj_sz = obj->size();
- HeapWord* obj_end = start + obj_sz;
-
- BitMap::idx_t start_idx = _cm->card_bitmap_index_for(start);
- BitMap::idx_t end_idx = _cm->card_bitmap_index_for(obj_end);
-
- // Note: if we're looking at the last region in heap - obj_end
- // could be actually just beyond the end of the heap; end_idx
- // will then correspond to a (non-existent) card that is also
- // just beyond the heap.
- if (_g1h->is_in_g1_reserved(obj_end) && !_ct_bs->is_card_aligned(obj_end)) {
- // end of object is not card aligned - increment to cover
- // all the cards spanned by the object
- end_idx += 1;
- }
-
- // Set the bits in the card BM for the cards spanned by this object.
- _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */);
-
- // Add the size of this object to the number of marked bytes.
- marked_bytes += (size_t)obj_sz * HeapWordSize;
-
- // This will happen if we are handling a humongous object that spans
- // several heap regions.
- if (obj_end > hr->end()) {
- break;
- }
- // Find the next marked object after this one.
- start = _bm->getNextMarkedWordAddress(obj_end, ntams);
- }
-
- // Mark the allocated-since-marking portion...
- HeapWord* top = hr->top();
- if (ntams < top) {
- BitMap::idx_t start_idx = _cm->card_bitmap_index_for(ntams);
- BitMap::idx_t end_idx = _cm->card_bitmap_index_for(top);
-
- // Note: if we're looking at the last region in heap - top
- // could be actually just beyond the end of the heap; end_idx
- // will then correspond to a (non-existent) card that is also
- // just beyond the heap.
- if (_g1h->is_in_g1_reserved(top) && !_ct_bs->is_card_aligned(top)) {
- // end of object is not card aligned - increment to cover
- // all the cards spanned by the object
- end_idx += 1;
- }
- _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */);
-
- // This definitely means the region has live objects.
- set_bit_for_region(hr);
- }
-
- // Update the live region bitmap.
- if (marked_bytes > 0) {
- set_bit_for_region(hr);
- }
-
- // Set the marked bytes for the current region so that
- // it can be queried by a calling verification routine
- _region_marked_bytes = marked_bytes;
-
- return false;
- }
-
- size_t region_marked_bytes() const { return _region_marked_bytes; }
-};
-
-// Heap region closure used for verifying the counting data
-// that was accumulated concurrently and aggregated during
-// the remark pause. This closure is applied to the heap
-// regions during the STW cleanup pause.
-
-class VerifyLiveObjectDataHRClosure: public HeapRegionClosure {
- G1CollectedHeap* _g1h;
- ConcurrentMark* _cm;
- CalcLiveObjectsClosure _calc_cl;
- BitMap* _region_bm; // Region BM to be verified
- BitMap* _card_bm; // Card BM to be verified
-
- BitMap* _exp_region_bm; // Expected Region BM values
- BitMap* _exp_card_bm; // Expected card BM values
-
- int _failures;
-
-public:
- VerifyLiveObjectDataHRClosure(G1CollectedHeap* g1h,
- BitMap* region_bm,
- BitMap* card_bm,
- BitMap* exp_region_bm,
- BitMap* exp_card_bm) :
- _g1h(g1h), _cm(g1h->concurrent_mark()),
- _calc_cl(_cm->nextMarkBitMap(), g1h, exp_region_bm, exp_card_bm),
- _region_bm(region_bm), _card_bm(card_bm),
- _exp_region_bm(exp_region_bm), _exp_card_bm(exp_card_bm),
- _failures(0) { }
-
- int failures() const { return _failures; }
-
- bool doHeapRegion(HeapRegion* hr) {
- int failures = 0;
-
- // Call the CalcLiveObjectsClosure to walk the marking bitmap for
- // this region and set the corresponding bits in the expected region
- // and card bitmaps.
- bool res = _calc_cl.doHeapRegion(hr);
- assert(res == false, "should be continuing");
-
- // Verify the marked bytes for this region.
- size_t exp_marked_bytes = _calc_cl.region_marked_bytes();
- size_t act_marked_bytes = hr->next_marked_bytes();
-
- if (exp_marked_bytes > act_marked_bytes) {
- if (hr->is_starts_humongous()) {
- // For start_humongous regions, the size of the whole object will be
- // in exp_marked_bytes.
- HeapRegion* region = hr;
- int num_regions;
- for (num_regions = 0; region != NULL; num_regions++) {
- region = _g1h->next_region_in_humongous(region);
- }
- if ((num_regions-1) * HeapRegion::GrainBytes >= exp_marked_bytes) {
- failures += 1;
- } else if (num_regions * HeapRegion::GrainBytes < exp_marked_bytes) {
- failures += 1;
- }
- } else {
- // We're not OK if expected marked bytes > actual marked bytes. It means
- // we have missed accounting some objects during the actual marking.
- failures += 1;
- }
- }
-
- // Verify the bit, for this region, in the actual and expected
- // (which was just calculated) region bit maps.
- // We're not OK if the bit in the calculated expected region
- // bitmap is set and the bit in the actual region bitmap is not.
- BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
-
- bool expected = _exp_region_bm->at(index);
- bool actual = _region_bm->at(index);
- if (expected && !actual) {
- failures += 1;
- }
-
- // Verify that the card bit maps for the cards spanned by the current
- // region match. We have an error if we have a set bit in the expected
- // bit map and the corresponding bit in the actual bitmap is not set.
-
- BitMap::idx_t start_idx = _cm->card_bitmap_index_for(hr->bottom());
- BitMap::idx_t end_idx = _cm->card_bitmap_index_for(hr->top());
-
- for (BitMap::idx_t i = start_idx; i < end_idx; i+=1) {
- expected = _exp_card_bm->at(i);
- actual = _card_bm->at(i);
-
- if (expected && !actual) {
- failures += 1;
- }
- }
-
- _failures += failures;
-
- // We could stop iteration over the heap when we
- // find the first violating region by returning true.
- return false;
- }
-};
-
-class G1ParVerifyFinalCountTask: public AbstractGangTask {
-protected:
- G1CollectedHeap* _g1h;
- ConcurrentMark* _cm;
- BitMap* _actual_region_bm;
- BitMap* _actual_card_bm;
-
- uint _n_workers;
-
- BitMap* _expected_region_bm;
- BitMap* _expected_card_bm;
-
- int _failures;
-
- HeapRegionClaimer _hrclaimer;
-
-public:
- G1ParVerifyFinalCountTask(G1CollectedHeap* g1h,
- BitMap* region_bm, BitMap* card_bm,
- BitMap* expected_region_bm, BitMap* expected_card_bm)
- : AbstractGangTask("G1 verify final counting"),
- _g1h(g1h), _cm(_g1h->concurrent_mark()),
- _actual_region_bm(region_bm), _actual_card_bm(card_bm),
- _expected_region_bm(expected_region_bm), _expected_card_bm(expected_card_bm),
- _failures(0),
- _n_workers(_g1h->workers()->active_workers()), _hrclaimer(_n_workers) {
- assert(VerifyDuringGC, "don't call this otherwise");
- assert(_expected_card_bm->size() == _actual_card_bm->size(), "sanity");
- assert(_expected_region_bm->size() == _actual_region_bm->size(), "sanity");
- }
-
- void work(uint worker_id) {
- assert(worker_id < _n_workers, "invariant");
-
- VerifyLiveObjectDataHRClosure verify_cl(_g1h,
- _actual_region_bm, _actual_card_bm,
- _expected_region_bm,
- _expected_card_bm);
-
- _g1h->heap_region_par_iterate(&verify_cl, worker_id, &_hrclaimer);
-
- Atomic::add(verify_cl.failures(), &_failures);
- }
-
- int failures() const { return _failures; }
-};
-
-// Closure that finalizes the liveness counting data.
-// Used during the cleanup pause.
-// Sets the bits corresponding to the interval [NTAMS, top]
-// (which contains the implicitly live objects) in the
-// card liveness bitmap. Also sets the bit for each region,
-// containing live data, in the region liveness bitmap.
-
-class FinalCountDataUpdateClosure: public CMCountDataClosureBase {
- public:
- FinalCountDataUpdateClosure(G1CollectedHeap* g1h,
- BitMap* region_bm,
- BitMap* card_bm) :
- CMCountDataClosureBase(g1h, region_bm, card_bm) { }
-
- bool doHeapRegion(HeapRegion* hr) {
- HeapWord* ntams = hr->next_top_at_mark_start();
- HeapWord* top = hr->top();
-
- assert(hr->bottom() <= ntams && ntams <= hr->end(), "Preconditions.");
-
- // Mark the allocated-since-marking portion...
- if (ntams < top) {
- // This definitely means the region has live objects.
- set_bit_for_region(hr);
-
- // Now set the bits in the card bitmap for [ntams, top)
- BitMap::idx_t start_idx = _cm->card_bitmap_index_for(ntams);
- BitMap::idx_t end_idx = _cm->card_bitmap_index_for(top);
-
- // Note: if we're looking at the last region in heap - top
- // could be actually just beyond the end of the heap; end_idx
- // will then correspond to a (non-existent) card that is also
- // just beyond the heap.
- if (_g1h->is_in_g1_reserved(top) && !_ct_bs->is_card_aligned(top)) {
- // end of object is not card aligned - increment to cover
- // all the cards spanned by the object
- end_idx += 1;
- }
-
- assert(end_idx <= _card_bm->size(),
- "oob: end_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT,
- end_idx, _card_bm->size());
- assert(start_idx < _card_bm->size(),
- "oob: start_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT,
- start_idx, _card_bm->size());
-
- _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */);
- }
-
- // Set the bit for the region if it contains live data
- if (hr->next_marked_bytes() > 0) {
- set_bit_for_region(hr);
- }
-
- return false;
- }
-};
-
-class G1ParFinalCountTask: public AbstractGangTask {
-protected:
- G1CollectedHeap* _g1h;
- ConcurrentMark* _cm;
- BitMap* _actual_region_bm;
- BitMap* _actual_card_bm;
-
- uint _n_workers;
- HeapRegionClaimer _hrclaimer;
-
-public:
- G1ParFinalCountTask(G1CollectedHeap* g1h, BitMap* region_bm, BitMap* card_bm)
- : AbstractGangTask("G1 final counting"),
- _g1h(g1h), _cm(_g1h->concurrent_mark()),
- _actual_region_bm(region_bm), _actual_card_bm(card_bm),
- _n_workers(_g1h->workers()->active_workers()), _hrclaimer(_n_workers) {
- }
-
- void work(uint worker_id) {
- assert(worker_id < _n_workers, "invariant");
-
- FinalCountDataUpdateClosure final_update_cl(_g1h,
- _actual_region_bm,
- _actual_card_bm);
-
- _g1h->heap_region_par_iterate(&final_update_cl, worker_id, &_hrclaimer);
- }
-};
-
-class G1NoteEndOfConcMarkClosure : public HeapRegionClosure {
- G1CollectedHeap* _g1;
- size_t _freed_bytes;
- FreeRegionList* _local_cleanup_list;
- uint _old_regions_removed;
- uint _humongous_regions_removed;
- HRRSCleanupTask* _hrrs_cleanup_task;
-
-public:
- G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
- FreeRegionList* local_cleanup_list,
- HRRSCleanupTask* hrrs_cleanup_task) :
- _g1(g1),
- _freed_bytes(0),
- _local_cleanup_list(local_cleanup_list),
- _old_regions_removed(0),
- _humongous_regions_removed(0),
- _hrrs_cleanup_task(hrrs_cleanup_task) { }
-
- size_t freed_bytes() { return _freed_bytes; }
- const uint old_regions_removed() { return _old_regions_removed; }
- const uint humongous_regions_removed() { return _humongous_regions_removed; }
-
- bool doHeapRegion(HeapRegion *hr) {
- if (hr->is_archive()) {
- return false;
- }
- // We use a claim value of zero here because all regions
- // were claimed with value 1 in the FinalCount task.
- _g1->reset_gc_time_stamps(hr);
- hr->note_end_of_marking();
-
- if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young()) {
- _freed_bytes += hr->used();
- hr->set_containing_set(NULL);
- if (hr->is_humongous()) {
- _humongous_regions_removed++;
- _g1->free_humongous_region(hr, _local_cleanup_list, true);
- } else {
- _old_regions_removed++;
- _g1->free_region(hr, _local_cleanup_list, true);
- }
- } else {
- hr->rem_set()->do_cleanup_work(_hrrs_cleanup_task);
- }
-
- return false;
- }
-};
-
-class G1ParNoteEndTask: public AbstractGangTask {
- friend class G1NoteEndOfConcMarkClosure;
-
-protected:
- G1CollectedHeap* _g1h;
- FreeRegionList* _cleanup_list;
- HeapRegionClaimer _hrclaimer;
-
-public:
- G1ParNoteEndTask(G1CollectedHeap* g1h, FreeRegionList* cleanup_list, uint n_workers) :
- AbstractGangTask("G1 note end"), _g1h(g1h), _cleanup_list(cleanup_list), _hrclaimer(n_workers) {
- }
-
- void work(uint worker_id) {
- FreeRegionList local_cleanup_list("Local Cleanup List");
- HRRSCleanupTask hrrs_cleanup_task;
- G1NoteEndOfConcMarkClosure g1_note_end(_g1h, &local_cleanup_list,
- &hrrs_cleanup_task);
- _g1h->heap_region_par_iterate(&g1_note_end, worker_id, &_hrclaimer);
- assert(g1_note_end.complete(), "Shouldn't have yielded!");
-
- // Now update the lists
- _g1h->remove_from_old_sets(g1_note_end.old_regions_removed(), g1_note_end.humongous_regions_removed());
- {
- MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
- _g1h->decrement_summary_bytes(g1_note_end.freed_bytes());
-
- // If we iterate over the global cleanup list at the end of
- // cleanup to do this printing we will not guarantee to only
- // generate output for the newly-reclaimed regions (the list
- // might not be empty at the beginning of cleanup; we might
- // still be working on its previous contents). So we do the
- // printing here, before we append the new regions to the global
- // cleanup list.
-
- G1HRPrinter* hr_printer = _g1h->hr_printer();
- if (hr_printer->is_active()) {
- FreeRegionListIterator iter(&local_cleanup_list);
- while (iter.more_available()) {
- HeapRegion* hr = iter.get_next();
- hr_printer->cleanup(hr);
- }
- }
-
- _cleanup_list->add_ordered(&local_cleanup_list);
- assert(local_cleanup_list.is_empty(), "post-condition");
-
- HeapRegionRemSet::finish_cleanup_task(&hrrs_cleanup_task);
- }
- }
-};
-
-void ConcurrentMark::cleanup() {
- // world is stopped at this checkpoint
- assert(SafepointSynchronize::is_at_safepoint(),
- "world should be stopped");
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
-
- // If a full collection has happened, we shouldn't do this.
- if (has_aborted()) {
- g1h->collector_state()->set_mark_in_progress(false); // So bitmap clearing isn't confused
- return;
- }
-
- g1h->verify_region_sets_optional();
-
- if (VerifyDuringGC) {
- HandleMark hm; // handle scope
- g1h->prepare_for_verify();
- Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (before)");
- }
- g1h->check_bitmaps("Cleanup Start");
-
- G1CollectorPolicy* g1p = g1h->g1_policy();
- g1p->record_concurrent_mark_cleanup_start();
-
- double start = os::elapsedTime();
-
- HeapRegionRemSet::reset_for_cleanup_tasks();
-
- // Do counting once more with the world stopped for good measure.
- G1ParFinalCountTask g1_par_count_task(g1h, &_region_bm, &_card_bm);
-
- g1h->workers()->run_task(&g1_par_count_task);
-
- if (VerifyDuringGC) {
- // Verify that the counting data accumulated during marking matches
- // that calculated by walking the marking bitmap.
-
- // Bitmaps to hold expected values
- BitMap expected_region_bm(_region_bm.size(), true);
- BitMap expected_card_bm(_card_bm.size(), true);
-
- G1ParVerifyFinalCountTask g1_par_verify_task(g1h,
- &_region_bm,
- &_card_bm,
- &expected_region_bm,
- &expected_card_bm);
-
- g1h->workers()->run_task(&g1_par_verify_task);
-
- guarantee(g1_par_verify_task.failures() == 0, "Unexpected accounting failures");
- }
-
- size_t start_used_bytes = g1h->used();
- g1h->collector_state()->set_mark_in_progress(false);
-
- double count_end = os::elapsedTime();
- double this_final_counting_time = (count_end - start);
- _total_counting_time += this_final_counting_time;
-
- if (log_is_enabled(Trace, gc, liveness)) {
- G1PrintRegionLivenessInfoClosure cl("Post-Marking");
- _g1h->heap_region_iterate(&cl);
- }
-
- // Install newly created mark bitMap as "prev".
- swapMarkBitMaps();
-
- g1h->reset_gc_time_stamp();
-
- uint n_workers = _g1h->workers()->active_workers();
-
- // Note end of marking in all heap regions.
- G1ParNoteEndTask g1_par_note_end_task(g1h, &_cleanup_list, n_workers);
- g1h->workers()->run_task(&g1_par_note_end_task);
- g1h->check_gc_time_stamps();
-
- if (!cleanup_list_is_empty()) {
- // The cleanup list is not empty, so we'll have to process it
- // concurrently. Notify anyone else that might be wanting free
- // regions that there will be more free regions coming soon.
- g1h->set_free_regions_coming();
- }
-
- // call below, since it affects the metric by which we sort the heap
- // regions.
- if (G1ScrubRemSets) {
- double rs_scrub_start = os::elapsedTime();
- g1h->scrub_rem_set(&_region_bm, &_card_bm);
- _total_rs_scrub_time += (os::elapsedTime() - rs_scrub_start);
- }
-
- // this will also free any regions totally full of garbage objects,
- // and sort the regions.
- g1h->g1_policy()->record_concurrent_mark_cleanup_end();
-
- // Statistics.
- double end = os::elapsedTime();
- _cleanup_times.add((end - start) * 1000.0);
-
- // Clean up will have freed any regions completely full of garbage.
- // Update the soft reference policy with the new heap occupancy.
- Universe::update_heap_info_at_gc();
-
- if (VerifyDuringGC) {
- HandleMark hm; // handle scope
- g1h->prepare_for_verify();
- Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (after)");
- }
-
- g1h->check_bitmaps("Cleanup End");
-
- g1h->verify_region_sets_optional();
-
- // We need to make this be a "collection" so any collection pause that
- // races with it goes around and waits for completeCleanup to finish.
- g1h->increment_total_collections();
-
- // Clean out dead classes and update Metaspace sizes.
- if (ClassUnloadingWithConcurrentMark) {
- ClassLoaderDataGraph::purge();
- }
- MetaspaceGC::compute_new_size();
-
- // We reclaimed old regions so we should calculate the sizes to make
- // sure we update the old gen/space data.
- g1h->g1mm()->update_sizes();
- g1h->allocation_context_stats().update_after_mark();
-
- g1h->trace_heap_after_concurrent_cycle();
-}
-
-void ConcurrentMark::completeCleanup() {
- if (has_aborted()) return;
-
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
-
- _cleanup_list.verify_optional();
- FreeRegionList tmp_free_list("Tmp Free List");
-
- log_develop_trace(gc, freelist)("G1ConcRegionFreeing [complete cleanup] : "
- "cleanup list has %u entries",
- _cleanup_list.length());
-
- // No one else should be accessing the _cleanup_list at this point,
- // so it is not necessary to take any locks
- while (!_cleanup_list.is_empty()) {
- HeapRegion* hr = _cleanup_list.remove_region(true /* from_head */);
- assert(hr != NULL, "Got NULL from a non-empty list");
- hr->par_clear();
- tmp_free_list.add_ordered(hr);
-
- // Instead of adding one region at a time to the secondary_free_list,
- // we accumulate them in the local list and move them a few at a
- // time. This also cuts down on the number of notify_all() calls
- // we do during this process. We'll also append the local list when
- // _cleanup_list is empty (which means we just removed the last
- // region from the _cleanup_list).
- if ((tmp_free_list.length() % G1SecondaryFreeListAppendLength == 0) ||
- _cleanup_list.is_empty()) {
- log_develop_trace(gc, freelist)("G1ConcRegionFreeing [complete cleanup] : "
- "appending %u entries to the secondary_free_list, "
- "cleanup list still has %u entries",
- tmp_free_list.length(),
- _cleanup_list.length());
-
- {
- MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag);
- g1h->secondary_free_list_add(&tmp_free_list);
- SecondaryFreeList_lock->notify_all();
- }
-#ifndef PRODUCT
- if (G1StressConcRegionFreeing) {
- for (uintx i = 0; i < G1StressConcRegionFreeingDelayMillis; ++i) {
- os::sleep(Thread::current(), (jlong) 1, false);
- }
- }
-#endif
- }
- }
- assert(tmp_free_list.is_empty(), "post-condition");
-}
-
-// Supporting Object and Oop closures for reference discovery
-// and processing in during marking
-
-bool G1CMIsAliveClosure::do_object_b(oop obj) {
- HeapWord* addr = (HeapWord*)obj;
- return addr != NULL &&
- (!_g1->is_in_g1_reserved(addr) || !_g1->is_obj_ill(obj));
-}
-
-// 'Keep Alive' oop closure used by both serial parallel reference processing.
-// Uses the CMTask associated with a worker thread (for serial reference
-// processing the CMTask for worker 0 is used) to preserve (mark) and
-// trace referent objects.
-//
-// Using the CMTask and embedded local queues avoids having the worker
-// threads operating on the global mark stack. This reduces the risk
-// of overflowing the stack - which we would rather avoid at this late
-// state. Also using the tasks' local queues removes the potential
-// of the workers interfering with each other that could occur if
-// operating on the global stack.
-
-class G1CMKeepAliveAndDrainClosure: public OopClosure {
- ConcurrentMark* _cm;
- CMTask* _task;
- int _ref_counter_limit;
- int _ref_counter;
- bool _is_serial;
- public:
- G1CMKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task, bool is_serial) :
- _cm(cm), _task(task), _is_serial(is_serial),
- _ref_counter_limit(G1RefProcDrainInterval) {
- assert(_ref_counter_limit > 0, "sanity");
- assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code");
- _ref_counter = _ref_counter_limit;
- }
-
- virtual void do_oop(narrowOop* p) { do_oop_work(p); }
- virtual void do_oop( oop* p) { do_oop_work(p); }
-
- template <class T> void do_oop_work(T* p) {
- if (!_cm->has_overflown()) {
- oop obj = oopDesc::load_decode_heap_oop(p);
- _task->deal_with_reference(obj);
- _ref_counter--;
-
- if (_ref_counter == 0) {
- // We have dealt with _ref_counter_limit references, pushing them
- // and objects reachable from them on to the local stack (and
- // possibly the global stack). Call CMTask::do_marking_step() to
- // process these entries.
- //
- // We call CMTask::do_marking_step() in a loop, which we'll exit if
- // there's nothing more to do (i.e. we're done with the entries that
- // were pushed as a result of the CMTask::deal_with_reference() calls
- // above) or we overflow.
- //
- // Note: CMTask::do_marking_step() can set the CMTask::has_aborted()
- // flag while there may still be some work to do. (See the comment at
- // the beginning of CMTask::do_marking_step() for those conditions -
- // one of which is reaching the specified time target.) It is only
- // when CMTask::do_marking_step() returns without setting the
- // has_aborted() flag that the marking step has completed.
- do {
- double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
- _task->do_marking_step(mark_step_duration_ms,
- false /* do_termination */,
- _is_serial);
- } while (_task->has_aborted() && !_cm->has_overflown());
- _ref_counter = _ref_counter_limit;
- }
- }
- }
-};
-
-// 'Drain' oop closure used by both serial and parallel reference processing.
-// Uses the CMTask associated with a given worker thread (for serial
-// reference processing the CMtask for worker 0 is used). Calls the
-// do_marking_step routine, with an unbelievably large timeout value,
-// to drain the marking data structures of the remaining entries
-// added by the 'keep alive' oop closure above.
-
-class G1CMDrainMarkingStackClosure: public VoidClosure {
- ConcurrentMark* _cm;
- CMTask* _task;
- bool _is_serial;
- public:
- G1CMDrainMarkingStackClosure(ConcurrentMark* cm, CMTask* task, bool is_serial) :
- _cm(cm), _task(task), _is_serial(is_serial) {
- assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code");
- }
-
- void do_void() {
- do {
- // We call CMTask::do_marking_step() to completely drain the local
- // and global marking stacks of entries pushed by the 'keep alive'
- // oop closure (an instance of G1CMKeepAliveAndDrainClosure above).
- //
- // CMTask::do_marking_step() is called in a loop, which we'll exit
- // if there's nothing more to do (i.e. we've completely drained the
- // entries that were pushed as a a result of applying the 'keep alive'
- // closure to the entries on the discovered ref lists) or we overflow
- // the global marking stack.
- //
- // Note: CMTask::do_marking_step() can set the CMTask::has_aborted()
- // flag while there may still be some work to do. (See the comment at
- // the beginning of CMTask::do_marking_step() for those conditions -
- // one of which is reaching the specified time target.) It is only
- // when CMTask::do_marking_step() returns without setting the
- // has_aborted() flag that the marking step has completed.
-
- _task->do_marking_step(1000000000.0 /* something very large */,
- true /* do_termination */,
- _is_serial);
- } while (_task->has_aborted() && !_cm->has_overflown());
- }
-};
-
-// Implementation of AbstractRefProcTaskExecutor for parallel
-// reference processing at the end of G1 concurrent marking
-
-class G1CMRefProcTaskExecutor: public AbstractRefProcTaskExecutor {
-private:
- G1CollectedHeap* _g1h;
- ConcurrentMark* _cm;
- WorkGang* _workers;
- uint _active_workers;
-
-public:
- G1CMRefProcTaskExecutor(G1CollectedHeap* g1h,
- ConcurrentMark* cm,
- WorkGang* workers,
- uint n_workers) :
- _g1h(g1h), _cm(cm),
- _workers(workers), _active_workers(n_workers) { }
-
- // Executes the given task using concurrent marking worker threads.
- virtual void execute(ProcessTask& task);
- virtual void execute(EnqueueTask& task);
-};
-
-class G1CMRefProcTaskProxy: public AbstractGangTask {
- typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
- ProcessTask& _proc_task;
- G1CollectedHeap* _g1h;
- ConcurrentMark* _cm;
-
-public:
- G1CMRefProcTaskProxy(ProcessTask& proc_task,
- G1CollectedHeap* g1h,
- ConcurrentMark* cm) :
- AbstractGangTask("Process reference objects in parallel"),
- _proc_task(proc_task), _g1h(g1h), _cm(cm) {
- ReferenceProcessor* rp = _g1h->ref_processor_cm();
- assert(rp->processing_is_mt(), "shouldn't be here otherwise");
- }
-
- virtual void work(uint worker_id) {
- ResourceMark rm;
- HandleMark hm;
- CMTask* task = _cm->task(worker_id);
- G1CMIsAliveClosure g1_is_alive(_g1h);
- G1CMKeepAliveAndDrainClosure g1_par_keep_alive(_cm, task, false /* is_serial */);
- G1CMDrainMarkingStackClosure g1_par_drain(_cm, task, false /* is_serial */);
-
- _proc_task.work(worker_id, g1_is_alive, g1_par_keep_alive, g1_par_drain);
- }
-};
-
-void G1CMRefProcTaskExecutor::execute(ProcessTask& proc_task) {
- assert(_workers != NULL, "Need parallel worker threads.");
- assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT");
-
- G1CMRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _cm);
-
- // We need to reset the concurrency level before each
- // proxy task execution, so that the termination protocol
- // and overflow handling in CMTask::do_marking_step() knows
- // how many workers to wait for.
- _cm->set_concurrency(_active_workers);
- _workers->run_task(&proc_task_proxy);
-}
-
-class G1CMRefEnqueueTaskProxy: public AbstractGangTask {
- typedef AbstractRefProcTaskExecutor::EnqueueTask EnqueueTask;
- EnqueueTask& _enq_task;
-
-public:
- G1CMRefEnqueueTaskProxy(EnqueueTask& enq_task) :
- AbstractGangTask("Enqueue reference objects in parallel"),
- _enq_task(enq_task) { }
-
- virtual void work(uint worker_id) {
- _enq_task.work(worker_id);
- }
-};
-
-void G1CMRefProcTaskExecutor::execute(EnqueueTask& enq_task) {
- assert(_workers != NULL, "Need parallel worker threads.");
- assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT");
-
- G1CMRefEnqueueTaskProxy enq_task_proxy(enq_task);
-
- // Not strictly necessary but...
- //
- // We need to reset the concurrency level before each
- // proxy task execution, so that the termination protocol
- // and overflow handling in CMTask::do_marking_step() knows
- // how many workers to wait for.
- _cm->set_concurrency(_active_workers);
- _workers->run_task(&enq_task_proxy);
-}
-
-void ConcurrentMark::weakRefsWorkParallelPart(BoolObjectClosure* is_alive, bool purged_classes) {
- G1CollectedHeap::heap()->parallel_cleaning(is_alive, true, true, purged_classes);
-}
-
-void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
- if (has_overflown()) {
- // Skip processing the discovered references if we have
- // overflown the global marking stack. Reference objects
- // only get discovered once so it is OK to not
- // de-populate the discovered reference lists. We could have,
- // but the only benefit would be that, when marking restarts,
- // less reference objects are discovered.
- return;
- }
-
- ResourceMark rm;
- HandleMark hm;
-
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
-
- // Is alive closure.
- G1CMIsAliveClosure g1_is_alive(g1h);
-
- // Inner scope to exclude the cleaning of the string and symbol
- // tables from the displayed time.
- {
- GCTraceTime(Debug, gc) trace("GC Ref Proc", g1h->gc_timer_cm());
-
- ReferenceProcessor* rp = g1h->ref_processor_cm();
-
- // See the comment in G1CollectedHeap::ref_processing_init()
- // about how reference processing currently works in G1.
-
- // Set the soft reference policy
- rp->setup_policy(clear_all_soft_refs);
- assert(_markStack.isEmpty(), "mark stack should be empty");
-
- // Instances of the 'Keep Alive' and 'Complete GC' closures used
- // in serial reference processing. Note these closures are also
- // used for serially processing (by the the current thread) the
- // JNI references during parallel reference processing.
- //
- // These closures do not need to synchronize with the worker
- // threads involved in parallel reference processing as these
- // instances are executed serially by the current thread (e.g.
- // reference processing is not multi-threaded and is thus
- // performed by the current thread instead of a gang worker).
- //
- // The gang tasks involved in parallel reference processing create
- // their own instances of these closures, which do their own
- // synchronization among themselves.
- G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0), true /* is_serial */);
- G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), true /* is_serial */);
-
- // We need at least one active thread. If reference processing
- // is not multi-threaded we use the current (VMThread) thread,
- // otherwise we use the work gang from the G1CollectedHeap and
- // we utilize all the worker threads we can.
- bool processing_is_mt = rp->processing_is_mt();
- uint active_workers = (processing_is_mt ? g1h->workers()->active_workers() : 1U);
- active_workers = MAX2(MIN2(active_workers, _max_worker_id), 1U);
-
- // Parallel processing task executor.
- G1CMRefProcTaskExecutor par_task_executor(g1h, this,
- g1h->workers(), active_workers);
- AbstractRefProcTaskExecutor* executor = (processing_is_mt ? &par_task_executor : NULL);
-
- // Set the concurrency level. The phase was already set prior to
- // executing the remark task.
- set_concurrency(active_workers);
-
- // Set the degree of MT processing here. If the discovery was done MT,
- // the number of threads involved during discovery could differ from
- // the number of active workers. This is OK as long as the discovered
- // Reference lists are balanced (see balance_all_queues() and balance_queues()).
- rp->set_active_mt_degree(active_workers);
-
- // Process the weak references.
- const ReferenceProcessorStats& stats =
- rp->process_discovered_references(&g1_is_alive,
- &g1_keep_alive,
- &g1_drain_mark_stack,
- executor,
- g1h->gc_timer_cm());
- g1h->gc_tracer_cm()->report_gc_reference_stats(stats);
-
- // The do_oop work routines of the keep_alive and drain_marking_stack
- // oop closures will set the has_overflown flag if we overflow the
- // global marking stack.
-
- assert(_markStack.overflow() || _markStack.isEmpty(),
- "mark stack should be empty (unless it overflowed)");
-
- if (_markStack.overflow()) {
- // This should have been done already when we tried to push an
- // entry on to the global mark stack. But let's do it again.
- set_has_overflown();
- }
-
- assert(rp->num_q() == active_workers, "why not");
-
- rp->enqueue_discovered_references(executor);
-
- rp->verify_no_references_recorded();
- assert(!rp->discovery_enabled(), "Post condition");
- }
-
- if (has_overflown()) {
- // We can not trust g1_is_alive if the marking stack overflowed
- return;
- }
-
- assert(_markStack.isEmpty(), "Marking should have completed");
-
- // Unload Klasses, String, Symbols, Code Cache, etc.
- {
- GCTraceTime(Debug, gc) trace("Unloading", g1h->gc_timer_cm());
-
- if (ClassUnloadingWithConcurrentMark) {
- bool purged_classes;
-
- {
- GCTraceTime(Trace, gc) trace("System Dictionary Unloading", g1h->gc_timer_cm());
- purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */);
- }
-
- {
- GCTraceTime(Trace, gc) trace("Parallel Unloading", g1h->gc_timer_cm());
- weakRefsWorkParallelPart(&g1_is_alive, purged_classes);
- }
- }
-
- if (G1StringDedup::is_enabled()) {
- GCTraceTime(Trace, gc) trace("String Deduplication Unlink", g1h->gc_timer_cm());
- G1StringDedup::unlink(&g1_is_alive);
- }
- }
-}
-
-void ConcurrentMark::swapMarkBitMaps() {
- CMBitMapRO* temp = _prevMarkBitMap;
- _prevMarkBitMap = (CMBitMapRO*)_nextMarkBitMap;
- _nextMarkBitMap = (CMBitMap*) temp;
-}
-
-// Closure for marking entries in SATB buffers.
-class CMSATBBufferClosure : public SATBBufferClosure {
-private:
- CMTask* _task;
- G1CollectedHeap* _g1h;
-
- // This is very similar to CMTask::deal_with_reference, but with
- // more relaxed requirements for the argument, so this must be more
- // circumspect about treating the argument as an object.
- void do_entry(void* entry) const {
- _task->increment_refs_reached();
- HeapRegion* hr = _g1h->heap_region_containing(entry);
- if (entry < hr->next_top_at_mark_start()) {
- // Until we get here, we don't know whether entry refers to a valid
- // object; it could instead have been a stale reference.
- oop obj = static_cast<oop>(entry);
- assert(obj->is_oop(true /* ignore mark word */),
- "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(obj));
- _task->make_reference_grey(obj, hr);
- }
- }
-
-public:
- CMSATBBufferClosure(CMTask* task, G1CollectedHeap* g1h)
- : _task(task), _g1h(g1h) { }
-
- virtual void do_buffer(void** buffer, size_t size) {
- for (size_t i = 0; i < size; ++i) {
- do_entry(buffer[i]);
- }
- }
-};
-
-class G1RemarkThreadsClosure : public ThreadClosure {
- CMSATBBufferClosure _cm_satb_cl;
- G1CMOopClosure _cm_cl;
- MarkingCodeBlobClosure _code_cl;
- int _thread_parity;
-
- public:
- G1RemarkThreadsClosure(G1CollectedHeap* g1h, CMTask* task) :
- _cm_satb_cl(task, g1h),
- _cm_cl(g1h, g1h->concurrent_mark(), task),
- _code_cl(&_cm_cl, !CodeBlobToOopClosure::FixRelocations),
- _thread_parity(Threads::thread_claim_parity()) {}
-
- void do_thread(Thread* thread) {
- if (thread->is_Java_thread()) {
- if (thread->claim_oops_do(true, _thread_parity)) {
- JavaThread* jt = (JavaThread*)thread;
-
- // In theory it should not be neccessary to explicitly walk the nmethods to find roots for concurrent marking
- // however the liveness of oops reachable from nmethods have very complex lifecycles:
- // * Alive if on the stack of an executing method
- // * Weakly reachable otherwise
- // Some objects reachable from nmethods, such as the class loader (or klass_holder) of the receiver should be
- // live by the SATB invariant but other oops recorded in nmethods may behave differently.
- jt->nmethods_do(&_code_cl);
-
- jt->satb_mark_queue().apply_closure_and_empty(&_cm_satb_cl);
- }
- } else if (thread->is_VM_thread()) {
- if (thread->claim_oops_do(true, _thread_parity)) {
- JavaThread::satb_mark_queue_set().shared_satb_queue()->apply_closure_and_empty(&_cm_satb_cl);
- }
- }
- }
-};
-
-class CMRemarkTask: public AbstractGangTask {
-private:
- ConcurrentMark* _cm;
-public:
- void work(uint worker_id) {
- // Since all available tasks are actually started, we should
- // only proceed if we're supposed to be active.
- if (worker_id < _cm->active_tasks()) {
- CMTask* task = _cm->task(worker_id);
- task->record_start_time();
- {
- ResourceMark rm;
- HandleMark hm;
-
- G1RemarkThreadsClosure threads_f(G1CollectedHeap::heap(), task);
- Threads::threads_do(&threads_f);
- }
-
- do {
- task->do_marking_step(1000000000.0 /* something very large */,
- true /* do_termination */,
- false /* is_serial */);
- } while (task->has_aborted() && !_cm->has_overflown());
- // If we overflow, then we do not want to restart. We instead
- // want to abort remark and do concurrent marking again.
- task->record_end_time();
- }
- }
-
- CMRemarkTask(ConcurrentMark* cm, uint active_workers) :
- AbstractGangTask("Par Remark"), _cm(cm) {
- _cm->terminator()->reset_for_reuse(active_workers);
- }
-};
-
-void ConcurrentMark::checkpointRootsFinalWork() {
- ResourceMark rm;
- HandleMark hm;
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
-
- GCTraceTime(Debug, gc) trace("Finalize Marking", g1h->gc_timer_cm());
-
- g1h->ensure_parsability(false);
-
- // this is remark, so we'll use up all active threads
- uint active_workers = g1h->workers()->active_workers();
- set_concurrency_and_phase(active_workers, false /* concurrent */);
- // Leave _parallel_marking_threads at it's
- // value originally calculated in the ConcurrentMark
- // constructor and pass values of the active workers
- // through the gang in the task.
-
- {
- StrongRootsScope srs(active_workers);
-
- CMRemarkTask remarkTask(this, active_workers);
- // We will start all available threads, even if we decide that the
- // active_workers will be fewer. The extra ones will just bail out
- // immediately.
- g1h->workers()->run_task(&remarkTask);
- }
-
- SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
- guarantee(has_overflown() ||
- satb_mq_set.completed_buffers_num() == 0,
- "Invariant: has_overflown = %s, num buffers = %d",
- BOOL_TO_STR(has_overflown()),
- satb_mq_set.completed_buffers_num());
-
- print_stats();
-}
-
-void ConcurrentMark::clearRangePrevBitmap(MemRegion mr) {
- // Note we are overriding the read-only view of the prev map here, via
- // the cast.
- ((CMBitMap*)_prevMarkBitMap)->clearRange(mr);
-}
-
-HeapRegion*
-ConcurrentMark::claim_region(uint worker_id) {
- // "checkpoint" the finger
- HeapWord* finger = _finger;
-
- // _heap_end will not change underneath our feet; it only changes at
- // yield points.
- while (finger < _heap_end) {
- assert(_g1h->is_in_g1_reserved(finger), "invariant");
-
- HeapRegion* curr_region = _g1h->heap_region_containing(finger);
-
- // Above heap_region_containing may return NULL as we always scan claim
- // until the end of the heap. In this case, just jump to the next region.
- HeapWord* end = curr_region != NULL ? curr_region->end() : finger + HeapRegion::GrainWords;
-
- // Is the gap between reading the finger and doing the CAS too long?
- HeapWord* res = (HeapWord*) Atomic::cmpxchg_ptr(end, &_finger, finger);
- if (res == finger && curr_region != NULL) {
- // we succeeded
- HeapWord* bottom = curr_region->bottom();
- HeapWord* limit = curr_region->next_top_at_mark_start();
-
- // notice that _finger == end cannot be guaranteed here since,
- // someone else might have moved the finger even further
- assert(_finger >= end, "the finger should have moved forward");
-
- if (limit > bottom) {
- return curr_region;
- } else {
- assert(limit == bottom,
- "the region limit should be at bottom");
- // we return NULL and the caller should try calling
- // claim_region() again.
- return NULL;
- }
- } else {
- assert(_finger > finger, "the finger should have moved forward");
- // read it again
- finger = _finger;
- }
- }
-
- return NULL;
-}
-
-#ifndef PRODUCT
-class VerifyNoCSetOops VALUE_OBJ_CLASS_SPEC {
-private:
- G1CollectedHeap* _g1h;
- const char* _phase;
- int _info;
-
-public:
- VerifyNoCSetOops(const char* phase, int info = -1) :
- _g1h(G1CollectedHeap::heap()),
- _phase(phase),
- _info(info)
- { }
-
- void operator()(oop obj) const {
- guarantee(obj->is_oop(),
- "Non-oop " PTR_FORMAT ", phase: %s, info: %d",
- p2i(obj), _phase, _info);
- guarantee(!_g1h->obj_in_cs(obj),
- "obj: " PTR_FORMAT " in CSet, phase: %s, info: %d",
- p2i(obj), _phase, _info);
- }
-};
-
-void ConcurrentMark::verify_no_cset_oops() {
- assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
- if (!G1CollectedHeap::heap()->collector_state()->mark_in_progress()) {
- return;
- }
-
- // Verify entries on the global mark stack
- _markStack.iterate(VerifyNoCSetOops("Stack"));
-
- // Verify entries on the task queues
- for (uint i = 0; i < _max_worker_id; ++i) {
- CMTaskQueue* queue = _task_queues->queue(i);
- queue->iterate(VerifyNoCSetOops("Queue", i));
- }
-
- // Verify the global finger
- HeapWord* global_finger = finger();
- if (global_finger != NULL && global_finger < _heap_end) {
- // Since we always iterate over all regions, we might get a NULL HeapRegion
- // here.
- HeapRegion* global_hr = _g1h->heap_region_containing(global_finger);
- guarantee(global_hr == NULL || global_finger == global_hr->bottom(),
- "global finger: " PTR_FORMAT " region: " HR_FORMAT,
- p2i(global_finger), HR_FORMAT_PARAMS(global_hr));
- }
-
- // Verify the task fingers
- assert(parallel_marking_threads() <= _max_worker_id, "sanity");
- for (uint i = 0; i < parallel_marking_threads(); ++i) {
- CMTask* task = _tasks[i];
- HeapWord* task_finger = task->finger();
- if (task_finger != NULL && task_finger < _heap_end) {
- // See above note on the global finger verification.
- HeapRegion* task_hr = _g1h->heap_region_containing(task_finger);
- guarantee(task_hr == NULL || task_finger == task_hr->bottom() ||
- !task_hr->in_collection_set(),
- "task finger: " PTR_FORMAT " region: " HR_FORMAT,
- p2i(task_finger), HR_FORMAT_PARAMS(task_hr));
- }
- }
-}
-#endif // PRODUCT
-
-// Aggregate the counting data that was constructed concurrently
-// with marking.
-class AggregateCountDataHRClosure: public HeapRegionClosure {
- G1CollectedHeap* _g1h;
- ConcurrentMark* _cm;
- CardTableModRefBS* _ct_bs;
- BitMap* _cm_card_bm;
- uint _max_worker_id;
-
- public:
- AggregateCountDataHRClosure(G1CollectedHeap* g1h,
- BitMap* cm_card_bm,
- uint max_worker_id) :
- _g1h(g1h), _cm(g1h->concurrent_mark()),
- _ct_bs(barrier_set_cast<CardTableModRefBS>(g1h->barrier_set())),
- _cm_card_bm(cm_card_bm), _max_worker_id(max_worker_id) { }
-
- bool doHeapRegion(HeapRegion* hr) {
- HeapWord* start = hr->bottom();
- HeapWord* limit = hr->next_top_at_mark_start();
- HeapWord* end = hr->end();
-
- assert(start <= limit && limit <= hr->top() && hr->top() <= hr->end(),
- "Preconditions not met - "
- "start: " PTR_FORMAT ", limit: " PTR_FORMAT ", "
- "top: " PTR_FORMAT ", end: " PTR_FORMAT,
- p2i(start), p2i(limit), p2i(hr->top()), p2i(hr->end()));
-
- assert(hr->next_marked_bytes() == 0, "Precondition");
-
- if (start == limit) {
- // NTAMS of this region has not been set so nothing to do.
- return false;
- }
-
- // 'start' should be in the heap.
- assert(_g1h->is_in_g1_reserved(start) && _ct_bs->is_card_aligned(start), "sanity");
- // 'end' *may* be just beyond the end of the heap (if hr is the last region)
- assert(!_g1h->is_in_g1_reserved(end) || _ct_bs->is_card_aligned(end), "sanity");
-
- BitMap::idx_t start_idx = _cm->card_bitmap_index_for(start);
- BitMap::idx_t limit_idx = _cm->card_bitmap_index_for(limit);
- BitMap::idx_t end_idx = _cm->card_bitmap_index_for(end);
-
- // If ntams is not card aligned then we bump card bitmap index
- // for limit so that we get the all the cards spanned by
- // the object ending at ntams.
- // Note: if this is the last region in the heap then ntams
- // could be actually just beyond the end of the the heap;
- // limit_idx will then correspond to a (non-existent) card
- // that is also outside the heap.
- if (_g1h->is_in_g1_reserved(limit) && !_ct_bs->is_card_aligned(limit)) {
- limit_idx += 1;
- }
-
- assert(limit_idx <= end_idx, "or else use atomics");
-
- // Aggregate the "stripe" in the count data associated with hr.
- uint hrm_index = hr->hrm_index();
- size_t marked_bytes = 0;
-
- for (uint i = 0; i < _max_worker_id; i += 1) {
- size_t* marked_bytes_array = _cm->count_marked_bytes_array_for(i);
- BitMap* task_card_bm = _cm->count_card_bitmap_for(i);
-
- // Fetch the marked_bytes in this region for task i and
- // add it to the running total for this region.
- marked_bytes += marked_bytes_array[hrm_index];
-
- // Now union the bitmaps[0,max_worker_id)[start_idx..limit_idx)
- // into the global card bitmap.
- BitMap::idx_t scan_idx = task_card_bm->get_next_one_offset(start_idx, limit_idx);
-
- while (scan_idx < limit_idx) {
- assert(task_card_bm->at(scan_idx) == true, "should be");
- _cm_card_bm->set_bit(scan_idx);
- assert(_cm_card_bm->at(scan_idx) == true, "should be");
-
- // BitMap::get_next_one_offset() can handle the case when
- // its left_offset parameter is greater than its right_offset
- // parameter. It does, however, have an early exit if
- // left_offset == right_offset. So let's limit the value
- // passed in for left offset here.
- BitMap::idx_t next_idx = MIN2(scan_idx + 1, limit_idx);
- scan_idx = task_card_bm->get_next_one_offset(next_idx, limit_idx);
- }
- }
-
- // Update the marked bytes for this region.
- hr->add_to_marked_bytes(marked_bytes);
-
- // Next heap region
- return false;
- }
-};
-
-class G1AggregateCountDataTask: public AbstractGangTask {
-protected:
- G1CollectedHeap* _g1h;
- ConcurrentMark* _cm;
- BitMap* _cm_card_bm;
- uint _max_worker_id;
- uint _active_workers;
- HeapRegionClaimer _hrclaimer;
-
-public:
- G1AggregateCountDataTask(G1CollectedHeap* g1h,
- ConcurrentMark* cm,
- BitMap* cm_card_bm,
- uint max_worker_id,
- uint n_workers) :
- AbstractGangTask("Count Aggregation"),
- _g1h(g1h), _cm(cm), _cm_card_bm(cm_card_bm),
- _max_worker_id(max_worker_id),
- _active_workers(n_workers),
- _hrclaimer(_active_workers) {
- }
-
- void work(uint worker_id) {
- AggregateCountDataHRClosure cl(_g1h, _cm_card_bm, _max_worker_id);
-
- _g1h->heap_region_par_iterate(&cl, worker_id, &_hrclaimer);
- }
-};
-
-
-void ConcurrentMark::aggregate_count_data() {
- uint n_workers = _g1h->workers()->active_workers();
-
- G1AggregateCountDataTask g1_par_agg_task(_g1h, this, &_card_bm,
- _max_worker_id, n_workers);
-
- _g1h->workers()->run_task(&g1_par_agg_task);
-}
-
-// Clear the per-worker arrays used to store the per-region counting data
-void ConcurrentMark::clear_all_count_data() {
- // Clear the global card bitmap - it will be filled during
- // liveness count aggregation (during remark) and the
- // final counting task.
- _card_bm.clear();
-
- // Clear the global region bitmap - it will be filled as part
- // of the final counting task.
- _region_bm.clear();
-
- uint max_regions = _g1h->max_regions();
- assert(_max_worker_id > 0, "uninitialized");
-
- for (uint i = 0; i < _max_worker_id; i += 1) {
- BitMap* task_card_bm = count_card_bitmap_for(i);
- size_t* marked_bytes_array = count_marked_bytes_array_for(i);
-
- assert(task_card_bm->size() == _card_bm.size(), "size mismatch");
- assert(marked_bytes_array != NULL, "uninitialized");
-
- memset(marked_bytes_array, 0, (size_t) max_regions * sizeof(size_t));
- task_card_bm->clear();
- }
-}
-
-void ConcurrentMark::print_stats() {
- if (!log_is_enabled(Debug, gc, stats)) {
- return;
- }
- log_debug(gc, stats)("---------------------------------------------------------------------");
- for (size_t i = 0; i < _active_tasks; ++i) {
- _tasks[i]->print_stats();
- log_debug(gc, stats)("---------------------------------------------------------------------");
- }
-}
-
-// abandon current marking iteration due to a Full GC
-void ConcurrentMark::abort() {
- if (!cmThread()->during_cycle() || _has_aborted) {
- // We haven't started a concurrent cycle or we have already aborted it. No need to do anything.
- return;
- }
-
- // Clear all marks in the next bitmap for the next marking cycle. This will allow us to skip the next
- // concurrent bitmap clearing.
- _nextMarkBitMap->clearAll();
-
- // Note we cannot clear the previous marking bitmap here
- // since VerifyDuringGC verifies the objects marked during
- // a full GC against the previous bitmap.
-
- // Clear the liveness counting data
- clear_all_count_data();
- // Empty mark stack
- reset_marking_state();
- for (uint i = 0; i < _max_worker_id; ++i) {
- _tasks[i]->clear_region_fields();
- }
- _first_overflow_barrier_sync.abort();
- _second_overflow_barrier_sync.abort();
- _has_aborted = true;
-
- SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
- satb_mq_set.abandon_partial_marking();
- // This can be called either during or outside marking, we'll read
- // the expected_active value from the SATB queue set.
- satb_mq_set.set_active_all_threads(
- false, /* new active value */
- satb_mq_set.is_active() /* expected_active */);
-
- _g1h->trace_heap_after_concurrent_cycle();
-
- // Close any open concurrent phase timing
- register_concurrent_phase_end();
-
- _g1h->register_concurrent_cycle_end();
-}
-
-static void print_ms_time_info(const char* prefix, const char* name,
- NumberSeq& ns) {
- log_trace(gc, marking)("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).",
- prefix, ns.num(), name, ns.sum()/1000.0, ns.avg());
- if (ns.num() > 0) {
- log_trace(gc, marking)("%s [std. dev = %8.2f ms, max = %8.2f ms]",
- prefix, ns.sd(), ns.maximum());
- }
-}
-
-void ConcurrentMark::print_summary_info() {
- LogHandle(gc, marking) log;
- if (!log.is_trace()) {
- return;
- }
-
- log.trace(" Concurrent marking:");
- print_ms_time_info(" ", "init marks", _init_times);
- print_ms_time_info(" ", "remarks", _remark_times);
- {
- print_ms_time_info(" ", "final marks", _remark_mark_times);
- print_ms_time_info(" ", "weak refs", _remark_weak_ref_times);
-
- }
- print_ms_time_info(" ", "cleanups", _cleanup_times);
- log.trace(" Final counting total time = %8.2f s (avg = %8.2f ms).",
- _total_counting_time, (_cleanup_times.num() > 0 ? _total_counting_time * 1000.0 / (double)_cleanup_times.num() : 0.0));
- if (G1ScrubRemSets) {
- log.trace(" RS scrub total time = %8.2f s (avg = %8.2f ms).",
- _total_rs_scrub_time, (_cleanup_times.num() > 0 ? _total_rs_scrub_time * 1000.0 / (double)_cleanup_times.num() : 0.0));
- }
- log.trace(" Total stop_world time = %8.2f s.",
- (_init_times.sum() + _remark_times.sum() + _cleanup_times.sum())/1000.0);
- log.trace(" Total concurrent time = %8.2f s (%8.2f s marking).",
- cmThread()->vtime_accum(), cmThread()->vtime_mark_accum());
-}
-
-void ConcurrentMark::print_worker_threads_on(outputStream* st) const {
- _parallel_workers->print_worker_threads_on(st);
-}
-
-void ConcurrentMark::print_on_error(outputStream* st) const {
- st->print_cr("Marking Bits (Prev, Next): (CMBitMap*) " PTR_FORMAT ", (CMBitMap*) " PTR_FORMAT,
- p2i(_prevMarkBitMap), p2i(_nextMarkBitMap));
- _prevMarkBitMap->print_on_error(st, " Prev Bits: ");
- _nextMarkBitMap->print_on_error(st, " Next Bits: ");
-}
-
-// We take a break if someone is trying to stop the world.
-bool ConcurrentMark::do_yield_check(uint worker_id) {
- if (SuspendibleThreadSet::should_yield()) {
- if (worker_id == 0) {
- _g1h->g1_policy()->record_concurrent_pause();
- }
- SuspendibleThreadSet::yield();
- return true;
- } else {
- return false;
- }
-}
-
-// Closure for iteration over bitmaps
-class CMBitMapClosure : public BitMapClosure {
-private:
- // the bitmap that is being iterated over
- CMBitMap* _nextMarkBitMap;
- ConcurrentMark* _cm;
- CMTask* _task;
-
-public:
- CMBitMapClosure(CMTask *task, ConcurrentMark* cm, CMBitMap* nextMarkBitMap) :
- _task(task), _cm(cm), _nextMarkBitMap(nextMarkBitMap) { }
-
- bool do_bit(size_t offset) {
- HeapWord* addr = _nextMarkBitMap->offsetToHeapWord(offset);
- assert(_nextMarkBitMap->isMarked(addr), "invariant");
- assert( addr < _cm->finger(), "invariant");
- assert(addr >= _task->finger(), "invariant");
-
- // We move that task's local finger along.
- _task->move_finger_to(addr);
-
- _task->scan_object(oop(addr));
- // we only partially drain the local queue and global stack
- _task->drain_local_queue(true);
- _task->drain_global_stack(true);
-
- // if the has_aborted flag has been raised, we need to bail out of
- // the iteration
- return !_task->has_aborted();
- }
-};
-
-static ReferenceProcessor* get_cm_oop_closure_ref_processor(G1CollectedHeap* g1h) {
- ReferenceProcessor* result = NULL;
- if (G1UseConcMarkReferenceProcessing) {
- result = g1h->ref_processor_cm();
- assert(result != NULL, "should not be NULL");
- }
- return result;
-}
-
-G1CMOopClosure::G1CMOopClosure(G1CollectedHeap* g1h,
- ConcurrentMark* cm,
- CMTask* task)
- : MetadataAwareOopClosure(get_cm_oop_closure_ref_processor(g1h)),
- _g1h(g1h), _cm(cm), _task(task)
-{ }
-
-void CMTask::setup_for_region(HeapRegion* hr) {
- assert(hr != NULL,
- "claim_region() should have filtered out NULL regions");
- _curr_region = hr;
- _finger = hr->bottom();
- update_region_limit();
-}
-
-void CMTask::update_region_limit() {
- HeapRegion* hr = _curr_region;
- HeapWord* bottom = hr->bottom();
- HeapWord* limit = hr->next_top_at_mark_start();
-
- if (limit == bottom) {
- // The region was collected underneath our feet.
- // We set the finger to bottom to ensure that the bitmap
- // iteration that will follow this will not do anything.
- // (this is not a condition that holds when we set the region up,
- // as the region is not supposed to be empty in the first place)
- _finger = bottom;
- } else if (limit >= _region_limit) {
- assert(limit >= _finger, "peace of mind");
- } else {
- assert(limit < _region_limit, "only way to get here");
- // This can happen under some pretty unusual circumstances. An
- // evacuation pause empties the region underneath our feet (NTAMS
- // at bottom). We then do some allocation in the region (NTAMS
- // stays at bottom), followed by the region being used as a GC
- // alloc region (NTAMS will move to top() and the objects
- // originally below it will be grayed). All objects now marked in
- // the region are explicitly grayed, if below the global finger,
- // and we do not need in fact to scan anything else. So, we simply
- // set _finger to be limit to ensure that the bitmap iteration
- // doesn't do anything.
- _finger = limit;
- }
-
- _region_limit = limit;
-}
-
-void CMTask::giveup_current_region() {
- assert(_curr_region != NULL, "invariant");
- clear_region_fields();
-}
-
-void CMTask::clear_region_fields() {
- // Values for these three fields that indicate that we're not
- // holding on to a region.
- _curr_region = NULL;
- _finger = NULL;
- _region_limit = NULL;
-}
-
-void CMTask::set_cm_oop_closure(G1CMOopClosure* cm_oop_closure) {
- if (cm_oop_closure == NULL) {
- assert(_cm_oop_closure != NULL, "invariant");
- } else {
- assert(_cm_oop_closure == NULL, "invariant");
- }
- _cm_oop_closure = cm_oop_closure;
-}
-
-void CMTask::reset(CMBitMap* nextMarkBitMap) {
- guarantee(nextMarkBitMap != NULL, "invariant");
- _nextMarkBitMap = nextMarkBitMap;
- clear_region_fields();
-
- _calls = 0;
- _elapsed_time_ms = 0.0;
- _termination_time_ms = 0.0;
- _termination_start_time_ms = 0.0;
-}
-
-bool CMTask::should_exit_termination() {
- regular_clock_call();
- // This is called when we are in the termination protocol. We should
- // quit if, for some reason, this task wants to abort or the global
- // stack is not empty (this means that we can get work from it).
- return !_cm->mark_stack_empty() || has_aborted();
-}
-
-void CMTask::reached_limit() {
- assert(_words_scanned >= _words_scanned_limit ||
- _refs_reached >= _refs_reached_limit ,
- "shouldn't have been called otherwise");
- regular_clock_call();
-}
-
-void CMTask::regular_clock_call() {
- if (has_aborted()) return;
-
- // First, we need to recalculate the words scanned and refs reached
- // limits for the next clock call.
- recalculate_limits();
-
- // During the regular clock call we do the following
-
- // (1) If an overflow has been flagged, then we abort.
- if (_cm->has_overflown()) {
- set_has_aborted();
- return;
- }
-
- // If we are not concurrent (i.e. we're doing remark) we don't need
- // to check anything else. The other steps are only needed during
- // the concurrent marking phase.
- if (!concurrent()) return;
-
- // (2) If marking has been aborted for Full GC, then we also abort.
- if (_cm->has_aborted()) {
- set_has_aborted();
- return;
- }
-
- double curr_time_ms = os::elapsedVTime() * 1000.0;
-
- // (4) We check whether we should yield. If we have to, then we abort.
- if (SuspendibleThreadSet::should_yield()) {
- // We should yield. To do this we abort the task. The caller is
- // responsible for yielding.
- set_has_aborted();
- return;
- }
-
- // (5) We check whether we've reached our time quota. If we have,
- // then we abort.
- double elapsed_time_ms = curr_time_ms - _start_time_ms;
- if (elapsed_time_ms > _time_target_ms) {
- set_has_aborted();
- _has_timed_out = true;
- return;
- }
-
- // (6) Finally, we check whether there are enough completed STAB
- // buffers available for processing. If there are, we abort.
- SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
- if (!_draining_satb_buffers && satb_mq_set.process_completed_buffers()) {
- // we do need to process SATB buffers, we'll abort and restart
- // the marking task to do so
- set_has_aborted();
- return;
- }
-}
-
-void CMTask::recalculate_limits() {
- _real_words_scanned_limit = _words_scanned + words_scanned_period;
- _words_scanned_limit = _real_words_scanned_limit;
-
- _real_refs_reached_limit = _refs_reached + refs_reached_period;
- _refs_reached_limit = _real_refs_reached_limit;
-}
-
-void CMTask::decrease_limits() {
- // This is called when we believe that we're going to do an infrequent
- // operation which will increase the per byte scanned cost (i.e. move
- // entries to/from the global stack). It basically tries to decrease the
- // scanning limit so that the clock is called earlier.
-
- _words_scanned_limit = _real_words_scanned_limit -
- 3 * words_scanned_period / 4;
- _refs_reached_limit = _real_refs_reached_limit -
- 3 * refs_reached_period / 4;
-}
-
-void CMTask::move_entries_to_global_stack() {
- // local array where we'll store the entries that will be popped
- // from the local queue
- oop buffer[global_stack_transfer_size];
-
- int n = 0;
- oop obj;
- while (n < global_stack_transfer_size && _task_queue->pop_local(obj)) {
- buffer[n] = obj;
- ++n;
- }
-
- if (n > 0) {
- // we popped at least one entry from the local queue
-
- if (!_cm->mark_stack_push(buffer, n)) {
- set_has_aborted();
- }
- }
-
- // this operation was quite expensive, so decrease the limits
- decrease_limits();
-}
-
-void CMTask::get_entries_from_global_stack() {
- // local array where we'll store the entries that will be popped
- // from the global stack.
- oop buffer[global_stack_transfer_size];
- int n;
- _cm->mark_stack_pop(buffer, global_stack_transfer_size, &n);
- assert(n <= global_stack_transfer_size,
- "we should not pop more than the given limit");
- if (n > 0) {
- // yes, we did actually pop at least one entry
- for (int i = 0; i < n; ++i) {
- bool success = _task_queue->push(buffer[i]);
- // We only call this when the local queue is empty or under a
- // given target limit. So, we do not expect this push to fail.
- assert(success, "invariant");
- }
- }
-
- // this operation was quite expensive, so decrease the limits
- decrease_limits();
-}
-
-void CMTask::drain_local_queue(bool partially) {
- if (has_aborted()) return;
-
- // Decide what the target size is, depending whether we're going to
- // drain it partially (so that other tasks can steal if they run out
- // of things to do) or totally (at the very end).
- size_t target_size;
- if (partially) {
- target_size = MIN2((size_t)_task_queue->max_elems()/3, GCDrainStackTargetSize);
- } else {
- target_size = 0;
- }
-
- if (_task_queue->size() > target_size) {
- oop obj;
- bool ret = _task_queue->pop_local(obj);
- while (ret) {
- assert(_g1h->is_in_g1_reserved((HeapWord*) obj), "invariant" );
- assert(!_g1h->is_on_master_free_list(
- _g1h->heap_region_containing((HeapWord*) obj)), "invariant");
-
- scan_object(obj);
-
- if (_task_queue->size() <= target_size || has_aborted()) {
- ret = false;
- } else {
- ret = _task_queue->pop_local(obj);
- }
- }
- }
-}
-
-void CMTask::drain_global_stack(bool partially) {
- if (has_aborted()) return;
-
- // We have a policy to drain the local queue before we attempt to
- // drain the global stack.
- assert(partially || _task_queue->size() == 0, "invariant");
-
- // Decide what the target size is, depending whether we're going to
- // drain it partially (so that other tasks can steal if they run out
- // of things to do) or totally (at the very end). Notice that,
- // because we move entries from the global stack in chunks or
- // because another task might be doing the same, we might in fact
- // drop below the target. But, this is not a problem.
- size_t target_size;
- if (partially) {
- target_size = _cm->partial_mark_stack_size_target();
- } else {
- target_size = 0;
- }
-
- if (_cm->mark_stack_size() > target_size) {
- while (!has_aborted() && _cm->mark_stack_size() > target_size) {
- get_entries_from_global_stack();
- drain_local_queue(partially);
- }
- }
-}
-
-// SATB Queue has several assumptions on whether to call the par or
-// non-par versions of the methods. this is why some of the code is
-// replicated. We should really get rid of the single-threaded version
-// of the code to simplify things.
-void CMTask::drain_satb_buffers() {
- if (has_aborted()) return;
-
- // We set this so that the regular clock knows that we're in the
- // middle of draining buffers and doesn't set the abort flag when it
- // notices that SATB buffers are available for draining. It'd be
- // very counter productive if it did that. :-)
- _draining_satb_buffers = true;
-
- CMSATBBufferClosure satb_cl(this, _g1h);
- SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
-
- // This keeps claiming and applying the closure to completed buffers
- // until we run out of buffers or we need to abort.
- while (!has_aborted() &&
- satb_mq_set.apply_closure_to_completed_buffer(&satb_cl)) {
- regular_clock_call();
- }
-
- _draining_satb_buffers = false;
-
- assert(has_aborted() ||
- concurrent() ||
- satb_mq_set.completed_buffers_num() == 0, "invariant");
-
- // again, this was a potentially expensive operation, decrease the
- // limits to get the regular clock call early
- decrease_limits();
-}
-
-void CMTask::print_stats() {
- log_debug(gc, stats)("Marking Stats, task = %u, calls = %d",
- _worker_id, _calls);
- log_debug(gc, stats)(" Elapsed time = %1.2lfms, Termination time = %1.2lfms",
- _elapsed_time_ms, _termination_time_ms);
- log_debug(gc, stats)(" Step Times (cum): num = %d, avg = %1.2lfms, sd = %1.2lfms",
- _step_times_ms.num(), _step_times_ms.avg(),
- _step_times_ms.sd());
- log_debug(gc, stats)(" max = %1.2lfms, total = %1.2lfms",
- _step_times_ms.maximum(), _step_times_ms.sum());
-}
-
-bool ConcurrentMark::try_stealing(uint worker_id, int* hash_seed, oop& obj) {
- return _task_queues->steal(worker_id, hash_seed, obj);
-}
-
-/*****************************************************************************
-
- The do_marking_step(time_target_ms, ...) method is the building
- block of the parallel marking framework. It can be called in parallel
- with other invocations of do_marking_step() on different tasks
- (but only one per task, obviously) and concurrently with the
- mutator threads, or during remark, hence it eliminates the need
- for two versions of the code. When called during remark, it will
- pick up from where the task left off during the concurrent marking
- phase. Interestingly, tasks are also claimable during evacuation
- pauses too, since do_marking_step() ensures that it aborts before
- it needs to yield.
-
- The data structures that it uses to do marking work are the
- following:
-
- (1) Marking Bitmap. If there are gray objects that appear only
- on the bitmap (this happens either when dealing with an overflow
- or when the initial marking phase has simply marked the roots
- and didn't push them on the stack), then tasks claim heap
- regions whose bitmap they then scan to find gray objects. A
- global finger indicates where the end of the last claimed region
- is. A local finger indicates how far into the region a task has
- scanned. The two fingers are used to determine how to gray an
- object (i.e. whether simply marking it is OK, as it will be
- visited by a task in the future, or whether it needs to be also
- pushed on a stack).
-
- (2) Local Queue. The local queue of the task which is accessed
- reasonably efficiently by the task. Other tasks can steal from
- it when they run out of work. Throughout the marking phase, a
- task attempts to keep its local queue short but not totally
- empty, so that entries are available for stealing by other
- tasks. Only when there is no more work, a task will totally
- drain its local queue.
-
- (3) Global Mark Stack. This handles local queue overflow. During
- marking only sets of entries are moved between it and the local
- queues, as access to it requires a mutex and more fine-grain
- interaction with it which might cause contention. If it
- overflows, then the marking phase should restart and iterate
- over the bitmap to identify gray objects. Throughout the marking
- phase, tasks attempt to keep the global mark stack at a small
- length but not totally empty, so that entries are available for
- popping by other tasks. Only when there is no more work, tasks
- will totally drain the global mark stack.
-
- (4) SATB Buffer Queue. This is where completed SATB buffers are
- made available. Buffers are regularly removed from this queue
- and scanned for roots, so that the queue doesn't get too
- long. During remark, all completed buffers are processed, as
- well as the filled in parts of any uncompleted buffers.
-
- The do_marking_step() method tries to abort when the time target
- has been reached. There are a few other cases when the
- do_marking_step() method also aborts:
-
- (1) When the marking phase has been aborted (after a Full GC).
-
- (2) When a global overflow (on the global stack) has been
- triggered. Before the task aborts, it will actually sync up with
- the other tasks to ensure that all the marking data structures
- (local queues, stacks, fingers etc.) are re-initialized so that
- when do_marking_step() completes, the marking phase can
- immediately restart.
-
- (3) When enough completed SATB buffers are available. The
- do_marking_step() method only tries to drain SATB buffers right
- at the beginning. So, if enough buffers are available, the
- marking step aborts and the SATB buffers are processed at
- the beginning of the next invocation.
-
- (4) To yield. when we have to yield then we abort and yield
- right at the end of do_marking_step(). This saves us from a lot
- of hassle as, by yielding we might allow a Full GC. If this
- happens then objects will be compacted underneath our feet, the
- heap might shrink, etc. We save checking for this by just
- aborting and doing the yield right at the end.
-
- From the above it follows that the do_marking_step() method should
- be called in a loop (or, otherwise, regularly) until it completes.
-
- If a marking step completes without its has_aborted() flag being
- true, it means it has completed the current marking phase (and
- also all other marking tasks have done so and have all synced up).
-
- A method called regular_clock_call() is invoked "regularly" (in
- sub ms intervals) throughout marking. It is this clock method that
- checks all the abort conditions which were mentioned above and
- decides when the task should abort. A work-based scheme is used to
- trigger this clock method: when the number of object words the
- marking phase has scanned or the number of references the marking
- phase has visited reach a given limit. Additional invocations to
- the method clock have been planted in a few other strategic places
- too. The initial reason for the clock method was to avoid calling
- vtime too regularly, as it is quite expensive. So, once it was in
- place, it was natural to piggy-back all the other conditions on it
- too and not constantly check them throughout the code.
-
- If do_termination is true then do_marking_step will enter its
- termination protocol.
-
- The value of is_serial must be true when do_marking_step is being
- called serially (i.e. by the VMThread) and do_marking_step should
- skip any synchronization in the termination and overflow code.
- Examples include the serial remark code and the serial reference
- processing closures.
-
- The value of is_serial must be false when do_marking_step is
- being called by any of the worker threads in a work gang.
- Examples include the concurrent marking code (CMMarkingTask),
- the MT remark code, and the MT reference processing closures.
-
- *****************************************************************************/
-
-void CMTask::do_marking_step(double time_target_ms,
- bool do_termination,
- bool is_serial) {
- assert(time_target_ms >= 1.0, "minimum granularity is 1ms");
- assert(concurrent() == _cm->concurrent(), "they should be the same");
-
- G1CollectorPolicy* g1_policy = _g1h->g1_policy();
- assert(_task_queues != NULL, "invariant");
- assert(_task_queue != NULL, "invariant");
- assert(_task_queues->queue(_worker_id) == _task_queue, "invariant");
-
- assert(!_claimed,
- "only one thread should claim this task at any one time");
-
- // OK, this doesn't safeguard again all possible scenarios, as it is
- // possible for two threads to set the _claimed flag at the same
- // time. But it is only for debugging purposes anyway and it will
- // catch most problems.
- _claimed = true;
-
- _start_time_ms = os::elapsedVTime() * 1000.0;
-
- // If do_stealing is true then do_marking_step will attempt to
- // steal work from the other CMTasks. It only makes sense to
- // enable stealing when the termination protocol is enabled
- // and do_marking_step() is not being called serially.
- bool do_stealing = do_termination && !is_serial;
-
- double diff_prediction_ms = _g1h->g1_policy()->predictor().get_new_prediction(&_marking_step_diffs_ms);
- _time_target_ms = time_target_ms - diff_prediction_ms;
-
- // set up the variables that are used in the work-based scheme to
- // call the regular clock method
- _words_scanned = 0;
- _refs_reached = 0;
- recalculate_limits();
-
- // clear all flags
- clear_has_aborted();
- _has_timed_out = false;
- _draining_satb_buffers = false;
-
- ++_calls;
-
- // Set up the bitmap and oop closures. Anything that uses them is
- // eventually called from this method, so it is OK to allocate these
- // statically.
- CMBitMapClosure bitmap_closure(this, _cm, _nextMarkBitMap);
- G1CMOopClosure cm_oop_closure(_g1h, _cm, this);
- set_cm_oop_closure(&cm_oop_closure);
-
- if (_cm->has_overflown()) {
- // This can happen if the mark stack overflows during a GC pause
- // and this task, after a yield point, restarts. We have to abort
- // as we need to get into the overflow protocol which happens
- // right at the end of this task.
- set_has_aborted();
- }
-
- // First drain any available SATB buffers. After this, we will not
- // look at SATB buffers before the next invocation of this method.
- // If enough completed SATB buffers are queued up, the regular clock
- // will abort this task so that it restarts.
- drain_satb_buffers();
- // ...then partially drain the local queue and the global stack
- drain_local_queue(true);
- drain_global_stack(true);
-
- do {
- if (!has_aborted() && _curr_region != NULL) {
- // This means that we're already holding on to a region.
- assert(_finger != NULL, "if region is not NULL, then the finger "
- "should not be NULL either");
-
- // We might have restarted this task after an evacuation pause
- // which might have evacuated the region we're holding on to
- // underneath our feet. Let's read its limit again to make sure
- // that we do not iterate over a region of the heap that
- // contains garbage (update_region_limit() will also move
- // _finger to the start of the region if it is found empty).
- update_region_limit();
- // We will start from _finger not from the start of the region,
- // as we might be restarting this task after aborting half-way
- // through scanning this region. In this case, _finger points to
- // the address where we last found a marked object. If this is a
- // fresh region, _finger points to start().
- MemRegion mr = MemRegion(_finger, _region_limit);
-
- assert(!_curr_region->is_humongous() || mr.start() == _curr_region->bottom(),
- "humongous regions should go around loop once only");
-
- // Some special cases:
- // If the memory region is empty, we can just give up the region.
- // If the current region is humongous then we only need to check
- // the bitmap for the bit associated with the start of the object,
- // scan the object if it's live, and give up the region.
- // Otherwise, let's iterate over the bitmap of the part of the region
- // that is left.
- // If the iteration is successful, give up the region.
- if (mr.is_empty()) {
- giveup_current_region();
- regular_clock_call();
- } else if (_curr_region->is_humongous() && mr.start() == _curr_region->bottom()) {
- if (_nextMarkBitMap->isMarked(mr.start())) {
- // The object is marked - apply the closure
- BitMap::idx_t offset = _nextMarkBitMap->heapWordToOffset(mr.start());
- bitmap_closure.do_bit(offset);
- }
- // Even if this task aborted while scanning the humongous object
- // we can (and should) give up the current region.
- giveup_current_region();
- regular_clock_call();
- } else if (_nextMarkBitMap->iterate(&bitmap_closure, mr)) {
- giveup_current_region();
- regular_clock_call();
- } else {
- assert(has_aborted(), "currently the only way to do so");
- // The only way to abort the bitmap iteration is to return
- // false from the do_bit() method. However, inside the
- // do_bit() method we move the _finger to point to the
- // object currently being looked at. So, if we bail out, we
- // have definitely set _finger to something non-null.
- assert(_finger != NULL, "invariant");
-
- // Region iteration was actually aborted. So now _finger
- // points to the address of the object we last scanned. If we
- // leave it there, when we restart this task, we will rescan
- // the object. It is easy to avoid this. We move the finger by
- // enough to point to the next possible object header (the
- // bitmap knows by how much we need to move it as it knows its
- // granularity).
- assert(_finger < _region_limit, "invariant");
- HeapWord* new_finger = _nextMarkBitMap->nextObject(_finger);
- // Check if bitmap iteration was aborted while scanning the last object
- if (new_finger >= _region_limit) {
- giveup_current_region();
- } else {
- move_finger_to(new_finger);
- }
- }
- }
- // At this point we have either completed iterating over the
- // region we were holding on to, or we have aborted.
-
- // We then partially drain the local queue and the global stack.
- // (Do we really need this?)
- drain_local_queue(true);
- drain_global_stack(true);
-
- // Read the note on the claim_region() method on why it might
- // return NULL with potentially more regions available for
- // claiming and why we have to check out_of_regions() to determine
- // whether we're done or not.
- while (!has_aborted() && _curr_region == NULL && !_cm->out_of_regions()) {
- // We are going to try to claim a new region. We should have
- // given up on the previous one.
- // Separated the asserts so that we know which one fires.
- assert(_curr_region == NULL, "invariant");
- assert(_finger == NULL, "invariant");
- assert(_region_limit == NULL, "invariant");
- HeapRegion* claimed_region = _cm->claim_region(_worker_id);
- if (claimed_region != NULL) {
- // Yes, we managed to claim one
- setup_for_region(claimed_region);
- assert(_curr_region == claimed_region, "invariant");
- }
- // It is important to call the regular clock here. It might take
- // a while to claim a region if, for example, we hit a large
- // block of empty regions. So we need to call the regular clock
- // method once round the loop to make sure it's called
- // frequently enough.
- regular_clock_call();
- }
-
- if (!has_aborted() && _curr_region == NULL) {
- assert(_cm->out_of_regions(),
- "at this point we should be out of regions");
- }
- } while ( _curr_region != NULL && !has_aborted());
-
- if (!has_aborted()) {
- // We cannot check whether the global stack is empty, since other
- // tasks might be pushing objects to it concurrently.
- assert(_cm->out_of_regions(),
- "at this point we should be out of regions");
- // Try to reduce the number of available SATB buffers so that
- // remark has less work to do.
- drain_satb_buffers();
- }
-
- // Since we've done everything else, we can now totally drain the
- // local queue and global stack.
- drain_local_queue(false);
- drain_global_stack(false);
-
- // Attempt at work stealing from other task's queues.
- if (do_stealing && !has_aborted()) {
- // We have not aborted. This means that we have finished all that
- // we could. Let's try to do some stealing...
-
- // We cannot check whether the global stack is empty, since other
- // tasks might be pushing objects to it concurrently.
- assert(_cm->out_of_regions() && _task_queue->size() == 0,
- "only way to reach here");
- while (!has_aborted()) {
- oop obj;
- if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) {
- assert(_nextMarkBitMap->isMarked((HeapWord*) obj),
- "any stolen object should be marked");
- scan_object(obj);
-
- // And since we're towards the end, let's totally drain the
- // local queue and global stack.
- drain_local_queue(false);
- drain_global_stack(false);
- } else {
- break;
- }
- }
- }
-
- // We still haven't aborted. Now, let's try to get into the
- // termination protocol.
- if (do_termination && !has_aborted()) {
- // We cannot check whether the global stack is empty, since other
- // tasks might be concurrently pushing objects on it.
- // Separated the asserts so that we know which one fires.
- assert(_cm->out_of_regions(), "only way to reach here");
- assert(_task_queue->size() == 0, "only way to reach here");
- _termination_start_time_ms = os::elapsedVTime() * 1000.0;
-
- // The CMTask class also extends the TerminatorTerminator class,
- // hence its should_exit_termination() method will also decide
- // whether to exit the termination protocol or not.
- bool finished = (is_serial ||
- _cm->terminator()->offer_termination(this));
- double termination_end_time_ms = os::elapsedVTime() * 1000.0;
- _termination_time_ms +=
- termination_end_time_ms - _termination_start_time_ms;
-
- if (finished) {
- // We're all done.
-
- if (_worker_id == 0) {
- // let's allow task 0 to do this
- if (concurrent()) {
- assert(_cm->concurrent_marking_in_progress(), "invariant");
- // we need to set this to false before the next
- // safepoint. This way we ensure that the marking phase
- // doesn't observe any more heap expansions.
- _cm->clear_concurrent_marking_in_progress();
- }
- }
-
- // We can now guarantee that the global stack is empty, since
- // all other tasks have finished. We separated the guarantees so
- // that, if a condition is false, we can immediately find out
- // which one.
- guarantee(_cm->out_of_regions(), "only way to reach here");
- guarantee(_cm->mark_stack_empty(), "only way to reach here");
- guarantee(_task_queue->size() == 0, "only way to reach here");
- guarantee(!_cm->has_overflown(), "only way to reach here");
- guarantee(!_cm->mark_stack_overflow(), "only way to reach here");
- } else {
- // Apparently there's more work to do. Let's abort this task. It
- // will restart it and we can hopefully find more things to do.
- set_has_aborted();
- }
- }
-
- // Mainly for debugging purposes to make sure that a pointer to the
- // closure which was statically allocated in this frame doesn't
- // escape it by accident.
- set_cm_oop_closure(NULL);
- double end_time_ms = os::elapsedVTime() * 1000.0;
- double elapsed_time_ms = end_time_ms - _start_time_ms;
- // Update the step history.
- _step_times_ms.add(elapsed_time_ms);
-
- if (has_aborted()) {
- // The task was aborted for some reason.
- if (_has_timed_out) {
- double diff_ms = elapsed_time_ms - _time_target_ms;
- // Keep statistics of how well we did with respect to hitting
- // our target only if we actually timed out (if we aborted for
- // other reasons, then the results might get skewed).
- _marking_step_diffs_ms.add(diff_ms);
- }
-
- if (_cm->has_overflown()) {
- // This is the interesting one. We aborted because a global
- // overflow was raised. This means we have to restart the
- // marking phase and start iterating over regions. However, in
- // order to do this we have to make sure that all tasks stop
- // what they are doing and re-initialize in a safe manner. We
- // will achieve this with the use of two barrier sync points.
-
- if (!is_serial) {
- // We only need to enter the sync barrier if being called
- // from a parallel context
- _cm->enter_first_sync_barrier(_worker_id);
-
- // When we exit this sync barrier we know that all tasks have
- // stopped doing marking work. So, it's now safe to
- // re-initialize our data structures. At the end of this method,
- // task 0 will clear the global data structures.
- }
-
- // We clear the local state of this task...
- clear_region_fields();
-
- if (!is_serial) {
- // ...and enter the second barrier.
- _cm->enter_second_sync_barrier(_worker_id);
- }
- // At this point, if we're during the concurrent phase of
- // marking, everything has been re-initialized and we're
- // ready to restart.
- }
- }
-
- _claimed = false;
-}
-
-CMTask::CMTask(uint worker_id,
- ConcurrentMark* cm,
- size_t* marked_bytes,
- BitMap* card_bm,
- CMTaskQueue* task_queue,
- CMTaskQueueSet* task_queues)
- : _g1h(G1CollectedHeap::heap()),
- _worker_id(worker_id), _cm(cm),
- _claimed(false),
- _nextMarkBitMap(NULL), _hash_seed(17),
- _task_queue(task_queue),
- _task_queues(task_queues),
- _cm_oop_closure(NULL),
- _marked_bytes_array(marked_bytes),
- _card_bm(card_bm) {
- guarantee(task_queue != NULL, "invariant");
- guarantee(task_queues != NULL, "invariant");
-
- _marking_step_diffs_ms.add(0.5);
-}
-
-// These are formatting macros that are used below to ensure
-// consistent formatting. The *_H_* versions are used to format the
-// header for a particular value and they should be kept consistent
-// with the corresponding macro. Also note that most of the macros add
-// the necessary white space (as a prefix) which makes them a bit
-// easier to compose.
-
-// All the output lines are prefixed with this string to be able to
-// identify them easily in a large log file.
-#define G1PPRL_LINE_PREFIX "###"
-
-#define G1PPRL_ADDR_BASE_FORMAT " " PTR_FORMAT "-" PTR_FORMAT
-#ifdef _LP64
-#define G1PPRL_ADDR_BASE_H_FORMAT " %37s"
-#else // _LP64
-#define G1PPRL_ADDR_BASE_H_FORMAT " %21s"
-#endif // _LP64
-
-// For per-region info
-#define G1PPRL_TYPE_FORMAT " %-4s"
-#define G1PPRL_TYPE_H_FORMAT " %4s"
-#define G1PPRL_BYTE_FORMAT " " SIZE_FORMAT_W(9)
-#define G1PPRL_BYTE_H_FORMAT " %9s"
-#define G1PPRL_DOUBLE_FORMAT " %14.1f"
-#define G1PPRL_DOUBLE_H_FORMAT " %14s"
-
-// For summary info
-#define G1PPRL_SUM_ADDR_FORMAT(tag) " " tag ":" G1PPRL_ADDR_BASE_FORMAT
-#define G1PPRL_SUM_BYTE_FORMAT(tag) " " tag ": " SIZE_FORMAT
-#define G1PPRL_SUM_MB_FORMAT(tag) " " tag ": %1.2f MB"
-#define G1PPRL_SUM_MB_PERC_FORMAT(tag) G1PPRL_SUM_MB_FORMAT(tag) " / %1.2f %%"
-
-G1PrintRegionLivenessInfoClosure::
-G1PrintRegionLivenessInfoClosure(const char* phase_name)
- : _total_used_bytes(0), _total_capacity_bytes(0),
- _total_prev_live_bytes(0), _total_next_live_bytes(0),
- _hum_used_bytes(0), _hum_capacity_bytes(0),
- _hum_prev_live_bytes(0), _hum_next_live_bytes(0),
- _total_remset_bytes(0), _total_strong_code_roots_bytes(0) {
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- MemRegion g1_reserved = g1h->g1_reserved();
- double now = os::elapsedTime();
-
- // Print the header of the output.
- log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now);
- log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" HEAP"
- G1PPRL_SUM_ADDR_FORMAT("reserved")
- G1PPRL_SUM_BYTE_FORMAT("region-size"),
- p2i(g1_reserved.start()), p2i(g1_reserved.end()),
- HeapRegion::GrainBytes);
- log_trace(gc, liveness)(G1PPRL_LINE_PREFIX);
- log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
- G1PPRL_TYPE_H_FORMAT
- G1PPRL_ADDR_BASE_H_FORMAT
- G1PPRL_BYTE_H_FORMAT
- G1PPRL_BYTE_H_FORMAT
- G1PPRL_BYTE_H_FORMAT
- G1PPRL_DOUBLE_H_FORMAT
- G1PPRL_BYTE_H_FORMAT
- G1PPRL_BYTE_H_FORMAT,
- "type", "address-range",
- "used", "prev-live", "next-live", "gc-eff",
- "remset", "code-roots");
- log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
- G1PPRL_TYPE_H_FORMAT
- G1PPRL_ADDR_BASE_H_FORMAT
- G1PPRL_BYTE_H_FORMAT
- G1PPRL_BYTE_H_FORMAT
- G1PPRL_BYTE_H_FORMAT
- G1PPRL_DOUBLE_H_FORMAT
- G1PPRL_BYTE_H_FORMAT
- G1PPRL_BYTE_H_FORMAT,
- "", "",
- "(bytes)", "(bytes)", "(bytes)", "(bytes/ms)",
- "(bytes)", "(bytes)");
-}
-
-// It takes as a parameter a reference to one of the _hum_* fields, it
-// deduces the corresponding value for a region in a humongous region
-// series (either the region size, or what's left if the _hum_* field
-// is < the region size), and updates the _hum_* field accordingly.
-size_t G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* hum_bytes) {
- size_t bytes = 0;
- // The > 0 check is to deal with the prev and next live bytes which
- // could be 0.
- if (*hum_bytes > 0) {
- bytes = MIN2(HeapRegion::GrainBytes, *hum_bytes);
- *hum_bytes -= bytes;
- }
- return bytes;
-}
-
-// It deduces the values for a region in a humongous region series
-// from the _hum_* fields and updates those accordingly. It assumes
-// that that _hum_* fields have already been set up from the "starts
-// humongous" region and we visit the regions in address order.
-void G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* used_bytes,
- size_t* capacity_bytes,
- size_t* prev_live_bytes,
- size_t* next_live_bytes) {
- assert(_hum_used_bytes > 0 && _hum_capacity_bytes > 0, "pre-condition");
- *used_bytes = get_hum_bytes(&_hum_used_bytes);
- *capacity_bytes = get_hum_bytes(&_hum_capacity_bytes);
- *prev_live_bytes = get_hum_bytes(&_hum_prev_live_bytes);
- *next_live_bytes = get_hum_bytes(&_hum_next_live_bytes);
-}
-
-bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) {
- const char* type = r->get_type_str();
- HeapWord* bottom = r->bottom();
- HeapWord* end = r->end();
- size_t capacity_bytes = r->capacity();
- size_t used_bytes = r->used();
- size_t prev_live_bytes = r->live_bytes();
- size_t next_live_bytes = r->next_live_bytes();
- double gc_eff = r->gc_efficiency();
- size_t remset_bytes = r->rem_set()->mem_size();
- size_t strong_code_roots_bytes = r->rem_set()->strong_code_roots_mem_size();
-
- if (r->is_starts_humongous()) {
- assert(_hum_used_bytes == 0 && _hum_capacity_bytes == 0 &&
- _hum_prev_live_bytes == 0 && _hum_next_live_bytes == 0,
- "they should have been zeroed after the last time we used them");
- // Set up the _hum_* fields.
- _hum_capacity_bytes = capacity_bytes;
- _hum_used_bytes = used_bytes;
- _hum_prev_live_bytes = prev_live_bytes;
- _hum_next_live_bytes = next_live_bytes;
- get_hum_bytes(&used_bytes, &capacity_bytes,
- &prev_live_bytes, &next_live_bytes);
- end = bottom + HeapRegion::GrainWords;
- } else if (r->is_continues_humongous()) {
- get_hum_bytes(&used_bytes, &capacity_bytes,
- &prev_live_bytes, &next_live_bytes);
- assert(end == bottom + HeapRegion::GrainWords, "invariant");
- }
-
- _total_used_bytes += used_bytes;
- _total_capacity_bytes += capacity_bytes;
- _total_prev_live_bytes += prev_live_bytes;
- _total_next_live_bytes += next_live_bytes;
- _total_remset_bytes += remset_bytes;
- _total_strong_code_roots_bytes += strong_code_roots_bytes;
-
- // Print a line for this particular region.
- log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
- G1PPRL_TYPE_FORMAT
- G1PPRL_ADDR_BASE_FORMAT
- G1PPRL_BYTE_FORMAT
- G1PPRL_BYTE_FORMAT
- G1PPRL_BYTE_FORMAT
- G1PPRL_DOUBLE_FORMAT
- G1PPRL_BYTE_FORMAT
- G1PPRL_BYTE_FORMAT,
- type, p2i(bottom), p2i(end),
- used_bytes, prev_live_bytes, next_live_bytes, gc_eff,
- remset_bytes, strong_code_roots_bytes);
-
- return false;
-}
-
-G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() {
- // add static memory usages to remembered set sizes
- _total_remset_bytes += HeapRegionRemSet::fl_mem_size() + HeapRegionRemSet::static_mem_size();
- // Print the footer of the output.
- log_trace(gc, liveness)(G1PPRL_LINE_PREFIX);
- log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
- " SUMMARY"
- G1PPRL_SUM_MB_FORMAT("capacity")
- G1PPRL_SUM_MB_PERC_FORMAT("used")
- G1PPRL_SUM_MB_PERC_FORMAT("prev-live")
- G1PPRL_SUM_MB_PERC_FORMAT("next-live")
- G1PPRL_SUM_MB_FORMAT("remset")
- G1PPRL_SUM_MB_FORMAT("code-roots"),
- bytes_to_mb(_total_capacity_bytes),
- bytes_to_mb(_total_used_bytes),
- perc(_total_used_bytes, _total_capacity_bytes),
- bytes_to_mb(_total_prev_live_bytes),
- perc(_total_prev_live_bytes, _total_capacity_bytes),
- bytes_to_mb(_total_next_live_bytes),
- perc(_total_next_live_bytes, _total_capacity_bytes),
- bytes_to_mb(_total_remset_bytes),
- bytes_to_mb(_total_strong_code_roots_bytes));
-}
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.hpp Mon Feb 22 09:02:14 2016 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1036 +0,0 @@
-/*
- * Copyright (c) 2001, 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.
- *
- */
-
-#ifndef SHARE_VM_GC_G1_CONCURRENTMARK_HPP
-#define SHARE_VM_GC_G1_CONCURRENTMARK_HPP
-
-#include "classfile/javaClasses.hpp"
-#include "gc/g1/g1RegionToSpaceMapper.hpp"
-#include "gc/g1/heapRegionSet.hpp"
-#include "gc/shared/taskqueue.hpp"
-
-class G1CollectedHeap;
-class CMBitMap;
-class CMTask;
-class ConcurrentMark;
-typedef GenericTaskQueue<oop, mtGC> CMTaskQueue;
-typedef GenericTaskQueueSet<CMTaskQueue, mtGC> CMTaskQueueSet;
-
-// Closure used by CM during concurrent reference discovery
-// and reference processing (during remarking) to determine
-// if a particular object is alive. It is primarily used
-// to determine if referents of discovered reference objects
-// are alive. An instance is also embedded into the
-// reference processor as the _is_alive_non_header field
-class G1CMIsAliveClosure: public BoolObjectClosure {
- G1CollectedHeap* _g1;
- public:
- G1CMIsAliveClosure(G1CollectedHeap* g1) : _g1(g1) { }
-
- bool do_object_b(oop obj);
-};
-
-// A generic CM bit map. This is essentially a wrapper around the BitMap
-// class, with one bit per (1<<_shifter) HeapWords.
-
-class CMBitMapRO VALUE_OBJ_CLASS_SPEC {
- protected:
- HeapWord* _bmStartWord; // base address of range covered by map
- size_t _bmWordSize; // map size (in #HeapWords covered)
- const int _shifter; // map to char or bit
- BitMap _bm; // the bit map itself
-
- public:
- // constructor
- CMBitMapRO(int shifter);
-
- // inquiries
- HeapWord* startWord() const { return _bmStartWord; }
- // the following is one past the last word in space
- HeapWord* endWord() const { return _bmStartWord + _bmWordSize; }
-
- // read marks
-
- bool isMarked(HeapWord* addr) const {
- assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
- "outside underlying space?");
- return _bm.at(heapWordToOffset(addr));
- }
-
- // iteration
- inline bool iterate(BitMapClosure* cl, MemRegion mr);
-
- // Return the address corresponding to the next marked bit at or after
- // "addr", and before "limit", if "limit" is non-NULL. If there is no
- // such bit, returns "limit" if that is non-NULL, or else "endWord()".
- HeapWord* getNextMarkedWordAddress(const HeapWord* addr,
- const HeapWord* limit = NULL) const;
-
- // conversion utilities
- HeapWord* offsetToHeapWord(size_t offset) const {
- return _bmStartWord + (offset << _shifter);
- }
- size_t heapWordToOffset(const HeapWord* addr) const {
- return pointer_delta(addr, _bmStartWord) >> _shifter;
- }
-
- // The argument addr should be the start address of a valid object
- HeapWord* nextObject(HeapWord* addr) {
- oop obj = (oop) addr;
- HeapWord* res = addr + obj->size();
- assert(offsetToHeapWord(heapWordToOffset(res)) == res, "sanity");
- return res;
- }
-
- void print_on_error(outputStream* st, const char* prefix) const;
-
- // debugging
- NOT_PRODUCT(bool covers(MemRegion rs) const;)
-};
-
-class CMBitMapMappingChangedListener : public G1MappingChangedListener {
- private:
- CMBitMap* _bm;
- public:
- CMBitMapMappingChangedListener() : _bm(NULL) {}
-
- void set_bitmap(CMBitMap* bm) { _bm = bm; }
-
- virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled);
-};
-
-class CMBitMap : public CMBitMapRO {
- private:
- CMBitMapMappingChangedListener _listener;
-
- public:
- static size_t compute_size(size_t heap_size);
- // Returns the amount of bytes on the heap between two marks in the bitmap.
- static size_t mark_distance();
- // Returns how many bytes (or bits) of the heap a single byte (or bit) of the
- // mark bitmap corresponds to. This is the same as the mark distance above.
- static size_t heap_map_factor() {
- return mark_distance();
- }
-
- CMBitMap() : CMBitMapRO(LogMinObjAlignment), _listener() { _listener.set_bitmap(this); }
-
- // Initializes the underlying BitMap to cover the given area.
- void initialize(MemRegion heap, G1RegionToSpaceMapper* storage);
-
- // Write marks.
- inline void mark(HeapWord* addr);
- inline void clear(HeapWord* addr);
- inline bool parMark(HeapWord* addr);
-
- void clearRange(MemRegion mr);
-
- // Clear the whole mark bitmap.
- void clearAll();
-};
-
-// Represents a marking stack used by ConcurrentMarking in the G1 collector.
-class CMMarkStack VALUE_OBJ_CLASS_SPEC {
- VirtualSpace _virtual_space; // Underlying backing store for actual stack
- ConcurrentMark* _cm;
- oop* _base; // bottom of stack
- jint _index; // one more than last occupied index
- jint _capacity; // max #elements
- jint _saved_index; // value of _index saved at start of GC
-
- bool _overflow;
- bool _should_expand;
-
- public:
- CMMarkStack(ConcurrentMark* cm);
- ~CMMarkStack();
-
- bool allocate(size_t capacity);
-
- // Pushes the first "n" elements of "ptr_arr" on the stack.
- // Locking impl: concurrency is allowed only with
- // "par_push_arr" and/or "par_pop_arr" operations, which use the same
- // locking strategy.
- void par_push_arr(oop* ptr_arr, int n);
-
- // If returns false, the array was empty. Otherwise, removes up to "max"
- // elements from the stack, and transfers them to "ptr_arr" in an
- // unspecified order. The actual number transferred is given in "n" ("n
- // == 0" is deliberately redundant with the return value.) Locking impl:
- // concurrency is allowed only with "par_push_arr" and/or "par_pop_arr"
- // operations, which use the same locking strategy.
- bool par_pop_arr(oop* ptr_arr, int max, int* n);
-
- bool isEmpty() { return _index == 0; }
- int maxElems() { return _capacity; }
-
- bool overflow() { return _overflow; }
- void clear_overflow() { _overflow = false; }
-
- bool should_expand() const { return _should_expand; }
- void set_should_expand();
-
- // Expand the stack, typically in response to an overflow condition
- void expand();
-
- int size() { return _index; }
-
- void setEmpty() { _index = 0; clear_overflow(); }
-
- // Record the current index.
- void note_start_of_gc();
-
- // Make sure that we have not added any entries to the stack during GC.
- void note_end_of_gc();
-
- // Apply fn to each oop in the mark stack, up to the bound recorded
- // via one of the above "note" functions. The mark stack must not
- // be modified while iterating.
- template<typename Fn> void iterate(Fn fn);
-};
-
-class YoungList;
-
-// Root Regions are regions that are not empty at the beginning of a
-// marking cycle and which we might collect during an evacuation pause
-// while the cycle is active. Given that, during evacuation pauses, we
-// do not copy objects that are explicitly marked, what we have to do
-// for the root regions is to scan them and mark all objects reachable
-// from them. According to the SATB assumptions, we only need to visit
-// each object once during marking. So, as long as we finish this scan
-// before the next evacuation pause, we can copy the objects from the
-// root regions without having to mark them or do anything else to them.
-//
-// Currently, we only support root region scanning once (at the start
-// of the marking cycle) and the root regions are all the survivor
-// regions populated during the initial-mark pause.
-class CMRootRegions VALUE_OBJ_CLASS_SPEC {
-private:
- YoungList* _young_list;
- ConcurrentMark* _cm;
-
- volatile bool _scan_in_progress;
- volatile bool _should_abort;
- HeapRegion* volatile _next_survivor;
-
-public:
- CMRootRegions();
- // We actually do most of the initialization in this method.
- void init(G1CollectedHeap* g1h, ConcurrentMark* cm);
-
- // Reset the claiming / scanning of the root regions.
- void prepare_for_scan();
-
- // Forces get_next() to return NULL so that the iteration aborts early.
- void abort() { _should_abort = true; }
-
- // Return true if the CM thread are actively scanning root regions,
- // false otherwise.
- bool scan_in_progress() { return _scan_in_progress; }
-
- // Claim the next root region to scan atomically, or return NULL if
- // all have been claimed.
- HeapRegion* claim_next();
-
- // Flag that we're done with root region scanning and notify anyone
- // who's waiting on it. If aborted is false, assume that all regions
- // have been claimed.
- void scan_finished();
-
- // If CM threads are still scanning root regions, wait until they
- // are done. Return true if we had to wait, false otherwise.
- bool wait_until_scan_finished();
-};
-
-class ConcurrentMarkThread;
-
-class ConcurrentMark: public CHeapObj<mtGC> {
- friend class CMMarkStack;
- friend class ConcurrentMarkThread;
- friend class CMTask;
- friend class CMBitMapClosure;
- friend class CMRemarkTask;
- friend class CMConcurrentMarkingTask;
- friend class G1ParNoteEndTask;
- friend class CalcLiveObjectsClosure;
- friend class G1CMRefProcTaskProxy;
- friend class G1CMRefProcTaskExecutor;
- friend class G1CMKeepAliveAndDrainClosure;
- friend class G1CMDrainMarkingStackClosure;
-
-protected:
- ConcurrentMarkThread* _cmThread; // The thread doing the work
- G1CollectedHeap* _g1h; // The heap
- uint _parallel_marking_threads; // The number of marking
- // threads we're using
- uint _max_parallel_marking_threads; // Max number of marking
- // threads we'll ever use
- double _sleep_factor; // How much we have to sleep, with
- // respect to the work we just did, to
- // meet the marking overhead goal
- double _marking_task_overhead; // Marking target overhead for
- // a single task
-
- FreeRegionList _cleanup_list;
-
- // Concurrent marking support structures
- CMBitMap _markBitMap1;
- CMBitMap _markBitMap2;
- CMBitMapRO* _prevMarkBitMap; // Completed mark bitmap
- CMBitMap* _nextMarkBitMap; // Under-construction mark bitmap
-
- BitMap _region_bm;
- BitMap _card_bm;
-
- // Heap bounds
- HeapWord* _heap_start;
- HeapWord* _heap_end;
-
- // Root region tracking and claiming
- CMRootRegions _root_regions;
-
- // For gray objects
- CMMarkStack _markStack; // Grey objects behind global finger
- HeapWord* volatile _finger; // The global finger, region aligned,
- // always points to the end of the
- // last claimed region
-
- // Marking tasks
- uint _max_worker_id;// Maximum worker id
- uint _active_tasks; // Task num currently active
- CMTask** _tasks; // Task queue array (max_worker_id len)
- CMTaskQueueSet* _task_queues; // Task queue set
- ParallelTaskTerminator _terminator; // For termination
-
- // Two sync barriers that are used to synchronize tasks when an
- // overflow occurs. The algorithm is the following. All tasks enter
- // the first one to ensure that they have all stopped manipulating
- // the global data structures. After they exit it, they re-initialize
- // their data structures and task 0 re-initializes the global data
- // structures. Then, they enter the second sync barrier. This
- // ensure, that no task starts doing work before all data
- // structures (local and global) have been re-initialized. When they
- // exit it, they are free to start working again.
- WorkGangBarrierSync _first_overflow_barrier_sync;
- WorkGangBarrierSync _second_overflow_barrier_sync;
-
- // This is set by any task, when an overflow on the global data
- // structures is detected
- volatile bool _has_overflown;
- // True: marking is concurrent, false: we're in remark
- volatile bool _concurrent;
- // Set at the end of a Full GC so that marking aborts
- volatile bool _has_aborted;
-
- // Used when remark aborts due to an overflow to indicate that
- // another concurrent marking phase should start
- volatile bool _restart_for_overflow;
-
- // This is true from the very start of concurrent marking until the
- // point when all the tasks complete their work. It is really used
- // to determine the points between the end of concurrent marking and
- // time of remark.
- volatile bool _concurrent_marking_in_progress;
-
- // Keep track of whether we have started concurrent phase or not.
- bool _concurrent_phase_started;
-
- // All of these times are in ms
- NumberSeq _init_times;
- NumberSeq _remark_times;
- NumberSeq _remark_mark_times;
- NumberSeq _remark_weak_ref_times;
- NumberSeq _cleanup_times;
- double _total_counting_time;
- double _total_rs_scrub_time;
-
- double* _accum_task_vtime; // Accumulated task vtime
-
- WorkGang* _parallel_workers;
-
- void weakRefsWorkParallelPart(BoolObjectClosure* is_alive, bool purged_classes);
- void weakRefsWork(bool clear_all_soft_refs);
-
- void swapMarkBitMaps();
-
- // It resets the global marking data structures, as well as the
- // task local ones; should be called during initial mark.
- void reset();
-
- // Resets all the marking data structures. Called when we have to restart
- // marking or when marking completes (via set_non_marking_state below).
- void reset_marking_state(bool clear_overflow = true);
-
- // We do this after we're done with marking so that the marking data
- // structures are initialized to a sensible and predictable state.
- void set_non_marking_state();
-
- // Called to indicate how many threads are currently active.
- void set_concurrency(uint active_tasks);
-
- // It should be called to indicate which phase we're in (concurrent
- // mark or remark) and how many threads are currently active.
- void set_concurrency_and_phase(uint active_tasks, bool concurrent);
-
- // Prints all gathered CM-related statistics
- void print_stats();
-
- bool cleanup_list_is_empty() {
- return _cleanup_list.is_empty();
- }
-
- // Accessor methods
- uint parallel_marking_threads() const { return _parallel_marking_threads; }
- uint max_parallel_marking_threads() const { return _max_parallel_marking_threads;}
- double sleep_factor() { return _sleep_factor; }
- double marking_task_overhead() { return _marking_task_overhead;}
-
- HeapWord* finger() { return _finger; }
- bool concurrent() { return _concurrent; }
- uint active_tasks() { return _active_tasks; }
- ParallelTaskTerminator* terminator() { return &_terminator; }
-
- // It claims the next available region to be scanned by a marking
- // task/thread. It might return NULL if the next region is empty or
- // we have run out of regions. In the latter case, out_of_regions()
- // determines whether we've really run out of regions or the task
- // should call claim_region() again. This might seem a bit
- // awkward. Originally, the code was written so that claim_region()
- // either successfully returned with a non-empty region or there
- // were no more regions to be claimed. The problem with this was
- // that, in certain circumstances, it iterated over large chunks of
- // the heap finding only empty regions and, while it was working, it
- // was preventing the calling task to call its regular clock
- // method. So, this way, each task will spend very little time in
- // claim_region() and is allowed to call the regular clock method
- // frequently.
- HeapRegion* claim_region(uint worker_id);
-
- // It determines whether we've run out of regions to scan. Note that
- // the finger can point past the heap end in case the heap was expanded
- // to satisfy an allocation without doing a GC. This is fine, because all
- // objects in those regions will be considered live anyway because of
- // SATB guarantees (i.e. their TAMS will be equal to bottom).
- bool out_of_regions() { return _finger >= _heap_end; }
-
- // Returns the task with the given id
- CMTask* task(int id) {
- assert(0 <= id && id < (int) _active_tasks,
- "task id not within active bounds");
- return _tasks[id];
- }
-
- // Returns the task queue with the given id
- CMTaskQueue* task_queue(int id) {
- assert(0 <= id && id < (int) _active_tasks,
- "task queue id not within active bounds");
- return (CMTaskQueue*) _task_queues->queue(id);
- }
-
- // Returns the task queue set
- CMTaskQueueSet* task_queues() { return _task_queues; }
-
- // Access / manipulation of the overflow flag which is set to
- // indicate that the global stack has overflown
- bool has_overflown() { return _has_overflown; }
- void set_has_overflown() { _has_overflown = true; }
- void clear_has_overflown() { _has_overflown = false; }
- bool restart_for_overflow() { return _restart_for_overflow; }
-
- // Methods to enter the two overflow sync barriers
- void enter_first_sync_barrier(uint worker_id);
- void enter_second_sync_barrier(uint worker_id);
-
- // Live Data Counting data structures...
- // These data structures are initialized at the start of
- // marking. They are written to while marking is active.
- // They are aggregated during remark; the aggregated values
- // are then used to populate the _region_bm, _card_bm, and
- // the total live bytes, which are then subsequently updated
- // during cleanup.
-
- // An array of bitmaps (one bit map per task). Each bitmap
- // is used to record the cards spanned by the live objects
- // marked by that task/worker.
- BitMap* _count_card_bitmaps;
-
- // Used to record the number of marked live bytes
- // (for each region, by worker thread).
- size_t** _count_marked_bytes;
-
- // Card index of the bottom of the G1 heap. Used for biasing indices into
- // the card bitmaps.
- intptr_t _heap_bottom_card_num;
-
- // Set to true when initialization is complete
- bool _completed_initialization;
-
-public:
- // Manipulation of the global mark stack.
- // The push and pop operations are used by tasks for transfers
- // between task-local queues and the global mark stack, and use
- // locking for concurrency safety.
- bool mark_stack_push(oop* arr, int n) {
- _markStack.par_push_arr(arr, n);
- if (_markStack.overflow()) {
- set_has_overflown();
- return false;
- }
- return true;
- }
- void mark_stack_pop(oop* arr, int max, int* n) {
- _markStack.par_pop_arr(arr, max, n);
- }
- size_t mark_stack_size() { return _markStack.size(); }
- size_t partial_mark_stack_size_target() { return _markStack.maxElems()/3; }
- bool mark_stack_overflow() { return _markStack.overflow(); }
- bool mark_stack_empty() { return _markStack.isEmpty(); }
-
- CMRootRegions* root_regions() { return &_root_regions; }
-
- bool concurrent_marking_in_progress() {
- return _concurrent_marking_in_progress;
- }
- void set_concurrent_marking_in_progress() {
- _concurrent_marking_in_progress = true;
- }
- void clear_concurrent_marking_in_progress() {
- _concurrent_marking_in_progress = false;
- }
-
- void register_concurrent_phase_start(const char* title);
- void register_concurrent_phase_end();
-
- void update_accum_task_vtime(int i, double vtime) {
- _accum_task_vtime[i] += vtime;
- }
-
- double all_task_accum_vtime() {
- double ret = 0.0;
- for (uint i = 0; i < _max_worker_id; ++i)
- ret += _accum_task_vtime[i];
- return ret;
- }
-
- // Attempts to steal an object from the task queues of other tasks
- bool try_stealing(uint worker_id, int* hash_seed, oop& obj);
-
- ConcurrentMark(G1CollectedHeap* g1h,
- G1RegionToSpaceMapper* prev_bitmap_storage,
- G1RegionToSpaceMapper* next_bitmap_storage);
- ~ConcurrentMark();
-
- ConcurrentMarkThread* cmThread() { return _cmThread; }
-
- CMBitMapRO* prevMarkBitMap() const { return _prevMarkBitMap; }
- CMBitMap* nextMarkBitMap() const { return _nextMarkBitMap; }
-
- // Returns the number of GC threads to be used in a concurrent
- // phase based on the number of GC threads being used in a STW
- // phase.
- uint scale_parallel_threads(uint n_par_threads);
-
- // Calculates the number of GC threads to be used in a concurrent phase.
- uint calc_parallel_marking_threads();
-
- // The following three are interaction between CM and
- // G1CollectedHeap
-
- // This notifies CM that a root during initial-mark needs to be
- // grayed. It is MT-safe. word_size is the size of the object in
- // words. It is passed explicitly as sometimes we cannot calculate
- // it from the given object because it might be in an inconsistent
- // state (e.g., in to-space and being copied). So the caller is
- // responsible for dealing with this issue (e.g., get the size from
- // the from-space image when the to-space image might be
- // inconsistent) and always passing the size. hr is the region that
- // contains the object and it's passed optionally from callers who
- // might already have it (no point in recalculating it).
- inline void grayRoot(oop obj,
- size_t word_size,
- uint worker_id,
- HeapRegion* hr = NULL);
-
- // Clear the next marking bitmap (will be called concurrently).
- void clearNextBitmap();
-
- // Return whether the next mark bitmap has no marks set. To be used for assertions
- // only. Will not yield to pause requests.
- bool nextMarkBitmapIsClear();
-
- // These two do the work that needs to be done before and after the
- // initial root checkpoint. Since this checkpoint can be done at two
- // different points (i.e. an explicit pause or piggy-backed on a
- // young collection), then it's nice to be able to easily share the
- // pre/post code. It might be the case that we can put everything in
- // the post method. TP
- void checkpointRootsInitialPre();
- void checkpointRootsInitialPost();
-
- // Scan all the root regions and mark everything reachable from
- // them.
- void scanRootRegions();
-
- // Scan a single root region and mark everything reachable from it.
- void scanRootRegion(HeapRegion* hr, uint worker_id);
-
- // Do concurrent phase of marking, to a tentative transitive closure.
- void markFromRoots();
-
- void checkpointRootsFinal(bool clear_all_soft_refs);
- void checkpointRootsFinalWork();
- void cleanup();
- void completeCleanup();
-
- // Mark in the previous bitmap. NB: this is usually read-only, so use
- // this carefully!
- inline void markPrev(oop p);
-
- // Clears marks for all objects in the given range, for the prev or
- // next bitmaps. NB: the previous bitmap is usually
- // read-only, so use this carefully!
- void clearRangePrevBitmap(MemRegion mr);
-
- // Notify data structures that a GC has started.
- void note_start_of_gc() {
- _markStack.note_start_of_gc();
- }
-
- // Notify data structures that a GC is finished.
- void note_end_of_gc() {
- _markStack.note_end_of_gc();
- }
-
- // Verify that there are no CSet oops on the stacks (taskqueues /
- // global mark stack) and fingers (global / per-task).
- // If marking is not in progress, it's a no-op.
- void verify_no_cset_oops() PRODUCT_RETURN;
-
- bool isPrevMarked(oop p) const {
- assert(p != NULL && p->is_oop(), "expected an oop");
- HeapWord* addr = (HeapWord*)p;
- assert(addr >= _prevMarkBitMap->startWord() ||
- addr < _prevMarkBitMap->endWord(), "in a region");
-
- return _prevMarkBitMap->isMarked(addr);
- }
-
- inline bool do_yield_check(uint worker_i = 0);
-
- // Called to abort the marking cycle after a Full GC takes place.
- void abort();
-
- bool has_aborted() { return _has_aborted; }
-
- void print_summary_info();
-
- void print_worker_threads_on(outputStream* st) const;
-
- void print_on_error(outputStream* st) const;
-
- // Liveness counting
-
- // Utility routine to set an exclusive range of cards on the given
- // card liveness bitmap
- inline void set_card_bitmap_range(BitMap* card_bm,
- BitMap::idx_t start_idx,
- BitMap::idx_t end_idx,
- bool is_par);
-
- // Returns the card number of the bottom of the G1 heap.
- // Used in biasing indices into accounting card bitmaps.
- intptr_t heap_bottom_card_num() const {
- return _heap_bottom_card_num;
- }
-
- // Returns the card bitmap for a given task or worker id.
- BitMap* count_card_bitmap_for(uint worker_id) {
- assert(worker_id < _max_worker_id, "oob");
- assert(_count_card_bitmaps != NULL, "uninitialized");
- BitMap* task_card_bm = &_count_card_bitmaps[worker_id];
- assert(task_card_bm->size() == _card_bm.size(), "size mismatch");
- return task_card_bm;
- }
-
- // Returns the array containing the marked bytes for each region,
- // for the given worker or task id.
- size_t* count_marked_bytes_array_for(uint worker_id) {
- assert(worker_id < _max_worker_id, "oob");
- assert(_count_marked_bytes != NULL, "uninitialized");
- size_t* marked_bytes_array = _count_marked_bytes[worker_id];
- assert(marked_bytes_array != NULL, "uninitialized");
- return marked_bytes_array;
- }
-
- // Returns the index in the liveness accounting card table bitmap
- // for the given address
- inline BitMap::idx_t card_bitmap_index_for(HeapWord* addr);
-
- // Counts the size of the given memory region in the the given
- // marked_bytes array slot for the given HeapRegion.
- // Sets the bits in the given card bitmap that are associated with the
- // cards that are spanned by the memory region.
- inline void count_region(MemRegion mr,
- HeapRegion* hr,
- size_t* marked_bytes_array,
- BitMap* task_card_bm);
-
- // Counts the given object in the given task/worker counting
- // data structures.
- inline void count_object(oop obj,
- HeapRegion* hr,
- size_t* marked_bytes_array,
- BitMap* task_card_bm,
- size_t word_size);
-
- // Attempts to mark the given object and, if successful, counts
- // the object in the given task/worker counting structures.
- inline bool par_mark_and_count(oop obj,
- HeapRegion* hr,
- size_t* marked_bytes_array,
- BitMap* task_card_bm);
-
- // Attempts to mark the given object and, if successful, counts
- // the object in the task/worker counting structures for the
- // given worker id.
- inline bool par_mark_and_count(oop obj,
- size_t word_size,
- HeapRegion* hr,
- uint worker_id);
-
- // Returns true if initialization was successfully completed.
- bool completed_initialization() const {
- return _completed_initialization;
- }
-
-protected:
- // Clear all the per-task bitmaps and arrays used to store the
- // counting data.
- void clear_all_count_data();
-
- // Aggregates the counting data for each worker/task
- // that was constructed while marking. Also sets
- // the amount of marked bytes for each region and
- // the top at concurrent mark count.
- void aggregate_count_data();
-
- // Verification routine
- void verify_count_data();
-};
-
-// A class representing a marking task.
-class CMTask : public TerminatorTerminator {
-private:
- enum PrivateConstants {
- // the regular clock call is called once the scanned words reaches
- // this limit
- words_scanned_period = 12*1024,
- // the regular clock call is called once the number of visited
- // references reaches this limit
- refs_reached_period = 384,
- // initial value for the hash seed, used in the work stealing code
- init_hash_seed = 17,
- // how many entries will be transferred between global stack and
- // local queues
- global_stack_transfer_size = 16
- };
-
- uint _worker_id;
- G1CollectedHeap* _g1h;
- ConcurrentMark* _cm;
- CMBitMap* _nextMarkBitMap;
- // the task queue of this task
- CMTaskQueue* _task_queue;
-private:
- // the task queue set---needed for stealing
- CMTaskQueueSet* _task_queues;
- // indicates whether the task has been claimed---this is only for
- // debugging purposes
- bool _claimed;
-
- // number of calls to this task
- int _calls;
-
- // when the virtual timer reaches this time, the marking step should
- // exit
- double _time_target_ms;
- // the start time of the current marking step
- double _start_time_ms;
-
- // the oop closure used for iterations over oops
- G1CMOopClosure* _cm_oop_closure;
-
- // the region this task is scanning, NULL if we're not scanning any
- HeapRegion* _curr_region;
- // the local finger of this task, NULL if we're not scanning a region
- HeapWord* _finger;
- // limit of the region this task is scanning, NULL if we're not scanning one
- HeapWord* _region_limit;
-
- // the number of words this task has scanned
- size_t _words_scanned;
- // When _words_scanned reaches this limit, the regular clock is
- // called. Notice that this might be decreased under certain
- // circumstances (i.e. when we believe that we did an expensive
- // operation).
- size_t _words_scanned_limit;
- // the initial value of _words_scanned_limit (i.e. what it was
- // before it was decreased).
- size_t _real_words_scanned_limit;
-
- // the number of references this task has visited
- size_t _refs_reached;
- // When _refs_reached reaches this limit, the regular clock is
- // called. Notice this this might be decreased under certain
- // circumstances (i.e. when we believe that we did an expensive
- // operation).
- size_t _refs_reached_limit;
- // the initial value of _refs_reached_limit (i.e. what it was before
- // it was decreased).
- size_t _real_refs_reached_limit;
-
- // used by the work stealing stuff
- int _hash_seed;
- // if this is true, then the task has aborted for some reason
- bool _has_aborted;
- // set when the task aborts because it has met its time quota
- bool _has_timed_out;
- // true when we're draining SATB buffers; this avoids the task
- // aborting due to SATB buffers being available (as we're already
- // dealing with them)
- bool _draining_satb_buffers;
-
- // number sequence of past step times
- NumberSeq _step_times_ms;
- // elapsed time of this task
- double _elapsed_time_ms;
- // termination time of this task
- double _termination_time_ms;
- // when this task got into the termination protocol
- double _termination_start_time_ms;
-
- // true when the task is during a concurrent phase, false when it is
- // in the remark phase (so, in the latter case, we do not have to
- // check all the things that we have to check during the concurrent
- // phase, i.e. SATB buffer availability...)
- bool _concurrent;
-
- TruncatedSeq _marking_step_diffs_ms;
-
- // Counting data structures. Embedding the task's marked_bytes_array
- // and card bitmap into the actual task saves having to go through
- // the ConcurrentMark object.
- size_t* _marked_bytes_array;
- BitMap* _card_bm;
-
- // it updates the local fields after this task has claimed
- // a new region to scan
- void setup_for_region(HeapRegion* hr);
- // it brings up-to-date the limit of the region
- void update_region_limit();
-
- // called when either the words scanned or the refs visited limit
- // has been reached
- void reached_limit();
- // recalculates the words scanned and refs visited limits
- void recalculate_limits();
- // decreases the words scanned and refs visited limits when we reach
- // an expensive operation
- void decrease_limits();
- // it checks whether the words scanned or refs visited reached their
- // respective limit and calls reached_limit() if they have
- void check_limits() {
- if (_words_scanned >= _words_scanned_limit ||
- _refs_reached >= _refs_reached_limit) {
- reached_limit();
- }
- }
- // this is supposed to be called regularly during a marking step as
- // it checks a bunch of conditions that might cause the marking step
- // to abort
- void regular_clock_call();
- bool concurrent() { return _concurrent; }
-
- // Test whether obj might have already been passed over by the
- // mark bitmap scan, and so needs to be pushed onto the mark stack.
- bool is_below_finger(oop obj, HeapWord* global_finger) const;
-
- template<bool scan> void process_grey_object(oop obj);
-
-public:
- // It resets the task; it should be called right at the beginning of
- // a marking phase.
- void reset(CMBitMap* _nextMarkBitMap);
- // it clears all the fields that correspond to a claimed region.
- void clear_region_fields();
-
- void set_concurrent(bool concurrent) { _concurrent = concurrent; }
-
- // The main method of this class which performs a marking step
- // trying not to exceed the given duration. However, it might exit
- // prematurely, according to some conditions (i.e. SATB buffers are
- // available for processing).
- void do_marking_step(double target_ms,
- bool do_termination,
- bool is_serial);
-
- // These two calls start and stop the timer
- void record_start_time() {
- _elapsed_time_ms = os::elapsedTime() * 1000.0;
- }
- void record_end_time() {
- _elapsed_time_ms = os::elapsedTime() * 1000.0 - _elapsed_time_ms;
- }
-
- // returns the worker ID associated with this task.
- uint worker_id() { return _worker_id; }
-
- // From TerminatorTerminator. It determines whether this task should
- // exit the termination protocol after it's entered it.
- virtual bool should_exit_termination();
-
- // Resets the local region fields after a task has finished scanning a
- // region; or when they have become stale as a result of the region
- // being evacuated.
- void giveup_current_region();
-
- HeapWord* finger() { return _finger; }
-
- bool has_aborted() { return _has_aborted; }
- void set_has_aborted() { _has_aborted = true; }
- void clear_has_aborted() { _has_aborted = false; }
- bool has_timed_out() { return _has_timed_out; }
- bool claimed() { return _claimed; }
-
- void set_cm_oop_closure(G1CMOopClosure* cm_oop_closure);
-
- // Increment the number of references this task has visited.
- void increment_refs_reached() { ++_refs_reached; }
-
- // Grey the object by marking it. If not already marked, push it on
- // the local queue if below the finger.
- // Precondition: obj is in region.
- // Precondition: obj is below region's NTAMS.
- inline void make_reference_grey(oop obj, HeapRegion* region);
-
- // Grey the object (by calling make_grey_reference) if required,
- // e.g. obj is below its containing region's NTAMS.
- // Precondition: obj is a valid heap object.
- inline void deal_with_reference(oop obj);
-
- // It scans an object and visits its children.
- inline void scan_object(oop obj);
-
- // It pushes an object on the local queue.
- inline void push(oop obj);
-
- // These two move entries to/from the global stack.
- void move_entries_to_global_stack();
- void get_entries_from_global_stack();
-
- // It pops and scans objects from the local queue. If partially is
- // true, then it stops when the queue size is of a given limit. If
- // partially is false, then it stops when the queue is empty.
- void drain_local_queue(bool partially);
- // It moves entries from the global stack to the local queue and
- // drains the local queue. If partially is true, then it stops when
- // both the global stack and the local queue reach a given size. If
- // partially if false, it tries to empty them totally.
- void drain_global_stack(bool partially);
- // It keeps picking SATB buffers and processing them until no SATB
- // buffers are available.
- void drain_satb_buffers();
-
- // moves the local finger to a new location
- inline void move_finger_to(HeapWord* new_finger) {
- assert(new_finger >= _finger && new_finger < _region_limit, "invariant");
- _finger = new_finger;
- }
-
- CMTask(uint worker_id,
- ConcurrentMark *cm,
- size_t* marked_bytes,
- BitMap* card_bm,
- CMTaskQueue* task_queue,
- CMTaskQueueSet* task_queues);
-
- // it prints statistics associated with this task
- void print_stats();
-};
-
-// Class that's used to to print out per-region liveness
-// information. It's currently used at the end of marking and also
-// after we sort the old regions at the end of the cleanup operation.
-class G1PrintRegionLivenessInfoClosure: public HeapRegionClosure {
-private:
- // Accumulators for these values.
- size_t _total_used_bytes;
- size_t _total_capacity_bytes;
- size_t _total_prev_live_bytes;
- size_t _total_next_live_bytes;
-
- // These are set up when we come across a "stars humongous" region
- // (as this is where most of this information is stored, not in the
- // subsequent "continues humongous" regions). After that, for every
- // region in a given humongous region series we deduce the right
- // values for it by simply subtracting the appropriate amount from
- // these fields. All these values should reach 0 after we've visited
- // the last region in the series.
- size_t _hum_used_bytes;
- size_t _hum_capacity_bytes;
- size_t _hum_prev_live_bytes;
- size_t _hum_next_live_bytes;
-
- // Accumulator for the remembered set size
- size_t _total_remset_bytes;
-
- // Accumulator for strong code roots memory size
- size_t _total_strong_code_roots_bytes;
-
- static double perc(size_t val, size_t total) {
- if (total == 0) {
- return 0.0;
- } else {
- return 100.0 * ((double) val / (double) total);
- }
- }
-
- static double bytes_to_mb(size_t val) {
- return (double) val / (double) M;
- }
-
- // See the .cpp file.
- size_t get_hum_bytes(size_t* hum_bytes);
- void get_hum_bytes(size_t* used_bytes, size_t* capacity_bytes,
- size_t* prev_live_bytes, size_t* next_live_bytes);
-
-public:
- // The header and footer are printed in the constructor and
- // destructor respectively.
- G1PrintRegionLivenessInfoClosure(const char* phase_name);
- virtual bool doHeapRegion(HeapRegion* r);
- ~G1PrintRegionLivenessInfoClosure();
-};
-
-#endif // SHARE_VM_GC_G1_CONCURRENTMARK_HPP
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,377 +0,0 @@
-/*
- * Copyright (c) 2001, 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.
- *
- */
-
-#ifndef SHARE_VM_GC_G1_CONCURRENTMARK_INLINE_HPP
-#define SHARE_VM_GC_G1_CONCURRENTMARK_INLINE_HPP
-
-#include "gc/g1/concurrentMark.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/shared/taskqueue.inline.hpp"
-
-// Utility routine to set an exclusive range of cards on the given
-// card liveness bitmap
-inline void ConcurrentMark::set_card_bitmap_range(BitMap* card_bm,
- BitMap::idx_t start_idx,
- BitMap::idx_t end_idx,
- bool is_par) {
-
- // Set the exclusive bit range [start_idx, end_idx).
- assert((end_idx - start_idx) > 0, "at least one card");
- assert(end_idx <= card_bm->size(), "sanity");
-
- // Silently clip the end index
- end_idx = MIN2(end_idx, card_bm->size());
-
- // For small ranges use a simple loop; otherwise use set_range or
- // use par_at_put_range (if parallel). The range is made up of the
- // cards that are spanned by an object/mem region so 8 cards will
- // allow up to object sizes up to 4K to be handled using the loop.
- if ((end_idx - start_idx) <= 8) {
- for (BitMap::idx_t i = start_idx; i < end_idx; i += 1) {
- if (is_par) {
- card_bm->par_set_bit(i);
- } else {
- card_bm->set_bit(i);
- }
- }
- } else {
- // Note BitMap::par_at_put_range() and BitMap::set_range() are exclusive.
- if (is_par) {
- card_bm->par_at_put_range(start_idx, end_idx, true);
- } else {
- card_bm->set_range(start_idx, end_idx);
- }
- }
-}
-
-// Returns the index in the liveness accounting card bitmap
-// for the given address
-inline BitMap::idx_t ConcurrentMark::card_bitmap_index_for(HeapWord* addr) {
- // Below, the term "card num" means the result of shifting an address
- // by the card shift -- address 0 corresponds to card number 0. One
- // must subtract the card num of the bottom of the heap to obtain a
- // card table index.
- intptr_t card_num = intptr_t(uintptr_t(addr) >> CardTableModRefBS::card_shift);
- return card_num - heap_bottom_card_num();
-}
-
-// Counts the given memory region in the given task/worker
-// counting data structures.
-inline void ConcurrentMark::count_region(MemRegion mr, HeapRegion* hr,
- size_t* marked_bytes_array,
- BitMap* task_card_bm) {
- G1CollectedHeap* g1h = _g1h;
- CardTableModRefBS* ct_bs = g1h->g1_barrier_set();
-
- HeapWord* start = mr.start();
- HeapWord* end = mr.end();
- size_t region_size_bytes = mr.byte_size();
- uint index = hr->hrm_index();
-
- assert(hr == g1h->heap_region_containing(start), "sanity");
- assert(marked_bytes_array != NULL, "pre-condition");
- assert(task_card_bm != NULL, "pre-condition");
-
- // Add to the task local marked bytes for this region.
- marked_bytes_array[index] += region_size_bytes;
-
- BitMap::idx_t start_idx = card_bitmap_index_for(start);
- BitMap::idx_t end_idx = card_bitmap_index_for(end);
-
- // Note: if we're looking at the last region in heap - end
- // could be actually just beyond the end of the heap; end_idx
- // will then correspond to a (non-existent) card that is also
- // just beyond the heap.
- if (g1h->is_in_g1_reserved(end) && !ct_bs->is_card_aligned(end)) {
- // end of region is not card aligned - increment to cover
- // all the cards spanned by the region.
- end_idx += 1;
- }
- // The card bitmap is task/worker specific => no need to use
- // the 'par' BitMap routines.
- // Set bits in the exclusive bit range [start_idx, end_idx).
- set_card_bitmap_range(task_card_bm, start_idx, end_idx, false /* is_par */);
-}
-
-// Counts the given object in the given task/worker counting data structures.
-inline void ConcurrentMark::count_object(oop obj,
- HeapRegion* hr,
- size_t* marked_bytes_array,
- BitMap* task_card_bm,
- size_t word_size) {
- assert(!hr->is_continues_humongous(), "Cannot enter count_object with continues humongous");
- if (!hr->is_starts_humongous()) {
- MemRegion mr((HeapWord*)obj, word_size);
- count_region(mr, hr, marked_bytes_array, task_card_bm);
- } else {
- do {
- MemRegion mr(hr->bottom(), hr->top());
- count_region(mr, hr, marked_bytes_array, task_card_bm);
- hr = _g1h->next_region_in_humongous(hr);
- } while (hr != NULL);
- }
-}
-
-// Attempts to mark the given object and, if successful, counts
-// the object in the given task/worker counting structures.
-inline bool ConcurrentMark::par_mark_and_count(oop obj,
- HeapRegion* hr,
- size_t* marked_bytes_array,
- BitMap* task_card_bm) {
- if (_nextMarkBitMap->parMark((HeapWord*)obj)) {
- // Update the task specific count data for the object.
- count_object(obj, hr, marked_bytes_array, task_card_bm, obj->size());
- return true;
- }
- return false;
-}
-
-// Attempts to mark the given object and, if successful, counts
-// the object in the task/worker counting structures for the
-// given worker id.
-inline bool ConcurrentMark::par_mark_and_count(oop obj,
- size_t word_size,
- HeapRegion* hr,
- uint worker_id) {
- if (_nextMarkBitMap->parMark((HeapWord*)obj)) {
- size_t* marked_bytes_array = count_marked_bytes_array_for(worker_id);
- BitMap* task_card_bm = count_card_bitmap_for(worker_id);
- count_object(obj, hr, marked_bytes_array, task_card_bm, word_size);
- return true;
- }
- return false;
-}
-
-inline bool CMBitMapRO::iterate(BitMapClosure* cl, MemRegion mr) {
- HeapWord* start_addr = MAX2(startWord(), mr.start());
- HeapWord* end_addr = MIN2(endWord(), mr.end());
-
- if (end_addr > start_addr) {
- // Right-open interval [start-offset, end-offset).
- BitMap::idx_t start_offset = heapWordToOffset(start_addr);
- BitMap::idx_t end_offset = heapWordToOffset(end_addr);
-
- start_offset = _bm.get_next_one_offset(start_offset, end_offset);
- while (start_offset < end_offset) {
- if (!cl->do_bit(start_offset)) {
- return false;
- }
- HeapWord* next_addr = MIN2(nextObject(offsetToHeapWord(start_offset)), end_addr);
- BitMap::idx_t next_offset = heapWordToOffset(next_addr);
- start_offset = _bm.get_next_one_offset(next_offset, end_offset);
- }
- }
- return true;
-}
-
-#define check_mark(addr) \
- assert(_bmStartWord <= (addr) && (addr) < (_bmStartWord + _bmWordSize), \
- "outside underlying space?"); \
- assert(G1CollectedHeap::heap()->is_in_exact(addr), \
- "Trying to access not available bitmap " PTR_FORMAT \
- " corresponding to " PTR_FORMAT " (%u)", \
- p2i(this), p2i(addr), G1CollectedHeap::heap()->addr_to_region(addr));
-
-inline void CMBitMap::mark(HeapWord* addr) {
- check_mark(addr);
- _bm.set_bit(heapWordToOffset(addr));
-}
-
-inline void CMBitMap::clear(HeapWord* addr) {
- check_mark(addr);
- _bm.clear_bit(heapWordToOffset(addr));
-}
-
-inline bool CMBitMap::parMark(HeapWord* addr) {
- check_mark(addr);
- return _bm.par_set_bit(heapWordToOffset(addr));
-}
-
-#undef check_mark
-
-template<typename Fn>
-inline void CMMarkStack::iterate(Fn fn) {
- assert(_saved_index == _index, "saved index: %d index: %d", _saved_index, _index);
- for (int i = 0; i < _index; ++i) {
- fn(_base[i]);
- }
-}
-
-// It scans an object and visits its children.
-inline void CMTask::scan_object(oop obj) { process_grey_object<true>(obj); }
-
-inline void CMTask::push(oop obj) {
- HeapWord* objAddr = (HeapWord*) obj;
- assert(_g1h->is_in_g1_reserved(objAddr), "invariant");
- assert(!_g1h->is_on_master_free_list(
- _g1h->heap_region_containing((HeapWord*) objAddr)), "invariant");
- assert(!_g1h->is_obj_ill(obj), "invariant");
- assert(_nextMarkBitMap->isMarked(objAddr), "invariant");
-
- if (!_task_queue->push(obj)) {
- // The local task queue looks full. We need to push some entries
- // to the global stack.
- move_entries_to_global_stack();
-
- // this should succeed since, even if we overflow the global
- // stack, we should have definitely removed some entries from the
- // local queue. So, there must be space on it.
- bool success = _task_queue->push(obj);
- assert(success, "invariant");
- }
-}
-
-inline bool CMTask::is_below_finger(oop obj, HeapWord* global_finger) const {
- // If obj is above the global finger, then the mark bitmap scan
- // will find it later, and no push is needed. Similarly, if we have
- // a current region and obj is between the local finger and the
- // end of the current region, then no push is needed. The tradeoff
- // of checking both vs only checking the global finger is that the
- // local check will be more accurate and so result in fewer pushes,
- // but may also be a little slower.
- HeapWord* objAddr = (HeapWord*)obj;
- if (_finger != NULL) {
- // We have a current region.
-
- // Finger and region values are all NULL or all non-NULL. We
- // use _finger to check since we immediately use its value.
- assert(_curr_region != NULL, "invariant");
- assert(_region_limit != NULL, "invariant");
- assert(_region_limit <= global_finger, "invariant");
-
- // True if obj is less than the local finger, or is between
- // the region limit and the global finger.
- if (objAddr < _finger) {
- return true;
- } else if (objAddr < _region_limit) {
- return false;
- } // Else check global finger.
- }
- // Check global finger.
- return objAddr < global_finger;
-}
-
-template<bool scan>
-inline void CMTask::process_grey_object(oop obj) {
- assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray");
- assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
-
- size_t obj_size = obj->size();
- _words_scanned += obj_size;
-
- if (scan) {
- obj->oop_iterate(_cm_oop_closure);
- }
- check_limits();
-}
-
-
-
-inline void CMTask::make_reference_grey(oop obj, HeapRegion* hr) {
- if (_cm->par_mark_and_count(obj, hr, _marked_bytes_array, _card_bm)) {
- // No OrderAccess:store_load() is needed. It is implicit in the
- // CAS done in CMBitMap::parMark() call in the routine above.
- HeapWord* global_finger = _cm->finger();
-
- // We only need to push a newly grey object on the mark
- // stack if it is in a section of memory the mark bitmap
- // scan has already examined. Mark bitmap scanning
- // maintains progress "fingers" for determining that.
- //
- // Notice that the global finger might be moving forward
- // concurrently. This is not a problem. In the worst case, we
- // mark the object while it is above the global finger and, by
- // the time we read the global finger, it has moved forward
- // past this object. In this case, the object will probably
- // be visited when a task is scanning the region and will also
- // be pushed on the stack. So, some duplicate work, but no
- // correctness problems.
- if (is_below_finger(obj, global_finger)) {
- if (obj->is_typeArray()) {
- // Immediately process arrays of primitive types, rather
- // than pushing on the mark stack. This keeps us from
- // adding humongous objects to the mark stack that might
- // be reclaimed before the entry is processed - see
- // selection of candidates for eager reclaim of humongous
- // objects. The cost of the additional type test is
- // mitigated by avoiding a trip through the mark stack,
- // by only doing a bookkeeping update and avoiding the
- // actual scan of the object - a typeArray contains no
- // references, and the metadata is built-in.
- process_grey_object<false>(obj);
- } else {
- push(obj);
- }
- }
- }
-}
-
-inline void CMTask::deal_with_reference(oop obj) {
- increment_refs_reached();
-
- HeapWord* objAddr = (HeapWord*) obj;
- assert(obj->is_oop_or_null(true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
- if (_g1h->is_in_g1_reserved(objAddr)) {
- assert(obj != NULL, "null check is implicit");
- if (!_nextMarkBitMap->isMarked(objAddr)) {
- // Only get the containing region if the object is not marked on the
- // bitmap (otherwise, it's a waste of time since we won't do
- // anything with it).
- HeapRegion* hr = _g1h->heap_region_containing(obj);
- if (!hr->obj_allocated_since_next_marking(obj)) {
- make_reference_grey(obj, hr);
- }
- }
- }
-}
-
-inline void ConcurrentMark::markPrev(oop p) {
- assert(!_prevMarkBitMap->isMarked((HeapWord*) p), "sanity");
- // Note we are overriding the read-only view of the prev map here, via
- // the cast.
- ((CMBitMap*)_prevMarkBitMap)->mark((HeapWord*) p);
-}
-
-inline void ConcurrentMark::grayRoot(oop obj, size_t word_size,
- uint worker_id, HeapRegion* hr) {
- assert(obj != NULL, "pre-condition");
- HeapWord* addr = (HeapWord*) obj;
- if (hr == NULL) {
- hr = _g1h->heap_region_containing(addr);
- } else {
- assert(hr->is_in(addr), "pre-condition");
- }
- assert(hr != NULL, "sanity");
- // Given that we're looking for a region that contains an object
- // header it's impossible to get back a HC region.
- assert(!hr->is_continues_humongous(), "sanity");
-
- if (addr < hr->next_top_at_mark_start()) {
- if (!_nextMarkBitMap->isMarked(addr)) {
- par_mark_and_count(obj, word_size, hr, worker_id);
- }
- }
-}
-
-#endif // SHARE_VM_GC_G1_CONCURRENTMARK_INLINE_HPP
--- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -43,7 +43,7 @@
SurrogateLockerThread*
ConcurrentMarkThread::_slt = NULL;
-ConcurrentMarkThread::ConcurrentMarkThread(ConcurrentMark* cm) :
+ConcurrentMarkThread::ConcurrentMarkThread(G1ConcurrentMark* cm) :
ConcurrentGCThread(),
_cm(cm),
_state(Idle),
@@ -56,10 +56,10 @@
class CMCheckpointRootsFinalClosure: public VoidClosure {
- ConcurrentMark* _cm;
+ G1ConcurrentMark* _cm;
public:
- CMCheckpointRootsFinalClosure(ConcurrentMark* cm) :
+ CMCheckpointRootsFinalClosure(G1ConcurrentMark* cm) :
_cm(cm) {}
void do_void(){
@@ -68,10 +68,10 @@
};
class CMCleanUp: public VoidClosure {
- ConcurrentMark* _cm;
+ G1ConcurrentMark* _cm;
public:
- CMCleanUp(ConcurrentMark* cm) :
+ CMCleanUp(G1ConcurrentMark* cm) :
_cm(cm) {}
void do_void(){
@@ -92,10 +92,10 @@
}
class GCConcPhaseTimer : StackObj {
- ConcurrentMark* _cm;
+ G1ConcurrentMark* _cm;
public:
- GCConcPhaseTimer(ConcurrentMark* cm, const char* title) : _cm(cm) {
+ GCConcPhaseTimer(G1ConcurrentMark* cm, const char* title) : _cm(cm) {
_cm->register_concurrent_phase_start(title);
}
--- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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,10 +27,10 @@
#include "gc/shared/concurrentGCThread.hpp"
-// The Concurrent Mark GC Thread triggers the parallel CMConcurrentMarkingTasks
+// The Concurrent Mark GC Thread triggers the parallel G1CMConcurrentMarkingTasks
// as well as handling various marking cleanup.
-class ConcurrentMark;
+class G1ConcurrentMark;
class G1CollectorPolicy;
class ConcurrentMarkThread: public ConcurrentGCThread {
@@ -45,7 +45,7 @@
virtual void run();
private:
- ConcurrentMark* _cm;
+ G1ConcurrentMark* _cm;
enum State {
Idle,
@@ -65,7 +65,7 @@
public:
// Constructor
- ConcurrentMarkThread(ConcurrentMark* cm);
+ ConcurrentMarkThread(G1ConcurrentMark* cm);
static void makeSurrogateLockerThread(TRAPS);
static SurrogateLockerThread* slt() { return _slt; }
@@ -75,7 +75,7 @@
// Marking virtual time so far this thread and concurrent marking tasks.
double vtime_mark_accum();
- ConcurrentMark* cm() { return _cm; }
+ G1ConcurrentMark* cm() { return _cm; }
void set_idle() { assert(_state != Started, "must not be starting a new cycle"); _state = Idle; }
bool idle() { return _state == Idle; }
--- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -25,8 +25,8 @@
#ifndef SHARE_VM_GC_G1_CONCURRENTMARKTHREAD_INLINE_HPP
#define SHARE_VM_GC_G1_CONCURRENTMARKTHREAD_INLINE_HPP
-#include "gc/g1/concurrentMark.hpp"
#include "gc/g1/concurrentMarkThread.hpp"
+#include "gc/g1/g1ConcurrentMark.hpp"
// Total virtual time so far.
inline double ConcurrentMarkThread::vtime_accum() {
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, 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
@@ -438,7 +438,7 @@
// If an end alignment was requested, insert filler objects.
if (end_alignment_in_bytes != 0) {
HeapWord* currtop = _allocation_region->top();
- HeapWord* newtop = (HeapWord*)align_pointer_up(currtop, end_alignment_in_bytes);
+ HeapWord* newtop = (HeapWord*)align_ptr_up(currtop, end_alignment_in_bytes);
size_t fill_size = pointer_delta(newtop, currtop);
if (fill_size != 0) {
if (fill_size < CollectedHeap::min_fill_size()) {
@@ -447,8 +447,8 @@
// region boundary because the max supported alignment is smaller than the min
// region size, and because the allocation code never leaves space smaller than
// the min_fill_size at the top of the current allocation region.
- newtop = (HeapWord*)align_pointer_up(currtop + CollectedHeap::min_fill_size(),
- end_alignment_in_bytes);
+ newtop = (HeapWord*)align_ptr_up(currtop + CollectedHeap::min_fill_size(),
+ end_alignment_in_bytes);
fill_size = pointer_delta(newtop, currtop);
}
HeapWord* fill = archive_mem_allocate(fill_size);
--- a/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, 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
@@ -74,10 +74,16 @@
static size_t static_mem_size() {
return sizeof(_purge_list);
}
+
+ size_t mem_size();
};
CodeRootSetTable* volatile CodeRootSetTable::_purge_list = NULL;
+size_t CodeRootSetTable::mem_size() {
+ return sizeof(CodeRootSetTable) + (entry_size() * number_of_entries()) + (sizeof(HashtableBucket<mtGC>) * table_size());
+}
+
CodeRootSetTable::Entry* CodeRootSetTable::new_entry(nmethod* nm) {
unsigned int hash = compute_hash(nm);
Entry* entry = (Entry*) new_entry_free_list();
@@ -232,7 +238,6 @@
OrderAccess::release_store_ptr(&_table, temp);
}
-
void G1CodeRootSet::purge() {
CodeRootSetTable::purge();
}
@@ -247,12 +252,13 @@
allocate_small_table();
}
added = _table->add(method);
- if (_length == Threshold) {
- move_to_large();
- }
if (added) {
+ if (_length == Threshold) {
+ move_to_large();
+ }
++_length;
}
+ assert(_length == (size_t)_table->number_of_entries(), "sizes should match");
}
bool G1CodeRootSet::remove(nmethod* method) {
@@ -266,11 +272,13 @@
clear();
}
}
+ assert((_length == 0 && _table == NULL) ||
+ (_length == (size_t)_table->number_of_entries()), "sizes should match");
return removed;
}
bool G1CodeRootSet::contains(nmethod* method) {
- CodeRootSetTable* table = load_acquire_table();
+ CodeRootSetTable* table = load_acquire_table(); // contains() may be called outside of lock, so ensure mem sync.
if (table != NULL) {
return table->contains(method);
}
@@ -284,8 +292,7 @@
}
size_t G1CodeRootSet::mem_size() {
- return sizeof(*this) +
- (_table != NULL ? sizeof(CodeRootSetTable) + _table->entry_size() * _length : 0);
+ return sizeof(*this) + (_table != NULL ? _table->mem_size() : 0);
}
void G1CodeRootSet::nmethods_do(CodeBlobClosure* blk) const {
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -38,6 +38,8 @@
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1EvacStats.inline.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
+#include "gc/g1/g1HeapTransition.hpp"
+#include "gc/g1/g1HeapVerifier.hpp"
#include "gc/g1/g1MarkSweep.hpp"
#include "gc/g1/g1OopClosures.inline.hpp"
#include "gc/g1/g1ParScanThreadState.inline.hpp"
@@ -60,7 +62,7 @@
#include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/generationSpec.hpp"
#include "gc/shared/isGCActiveMark.hpp"
-#include "gc/shared/referenceProcessor.hpp"
+#include "gc/shared/referenceProcessor.inline.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
@@ -399,7 +401,7 @@
assert(hr->bottom() < obj_top && obj_top <= hr->end(),
"obj_top should be in last region");
- check_bitmaps("Humongous Region Allocation", first_hr);
+ _verifier->check_bitmaps("Humongous Region Allocation", first_hr);
assert(words_not_fillable == 0 ||
first_hr->bottom() + word_size_sum - words_not_fillable == hr->top(),
@@ -427,7 +429,7 @@
HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size, AllocationContext_t context) {
assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */);
- verify_region_sets_optional();
+ _verifier->verify_region_sets_optional();
uint first = G1_NO_HRM_INDEX;
uint obj_regions = (uint) humongous_obj_size_in_regions(word_size);
@@ -501,7 +503,7 @@
g1mm()->update_sizes();
}
- verify_region_sets_optional();
+ _verifier->verify_region_sets_optional();
return result;
}
@@ -1230,7 +1232,7 @@
size_t metadata_prev_used = MetaspaceAux::used_bytes();
- verify_region_sets_optional();
+ _verifier->verify_region_sets_optional();
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
collector_policy()->should_clear_all_soft_refs();
@@ -1249,6 +1251,7 @@
TraceCollectorStats tcs(g1mm()->full_collection_counters());
TraceMemoryManagerStats tms(true /* fullGC */, gc_cause());
+ G1HeapTransition heap_transition(this);
g1_policy()->record_full_collection_start();
// Note: When we have a more flexible GC logging framework that
@@ -1271,9 +1274,9 @@
assert(used() == recalculate_used(), "Should be equal");
- verify_before_gc();
-
- check_bitmaps("Full GC Start");
+ _verifier->verify_before_gc();
+
+ _verifier->check_bitmaps("Full GC Start");
pre_full_gc_dump(gc_timer);
#if defined(COMPILER2) || INCLUDE_JVMCI
@@ -1408,21 +1411,21 @@
increment_old_marking_cycles_completed(false /* concurrent */);
_hrm.verify_optional();
- verify_region_sets_optional();
-
- verify_after_gc();
+ _verifier->verify_region_sets_optional();
+
+ _verifier->verify_after_gc();
// Clear the previous marking bitmap, if needed for bitmap verification.
// Note we cannot do this when we clear the next marking bitmap in
- // ConcurrentMark::abort() above since VerifyDuringGC verifies the
+ // G1ConcurrentMark::abort() above since VerifyDuringGC verifies the
// objects marked during a full GC against the previous bitmap.
// But we need to clear it before calling check_bitmaps below since
// the full GC has compacted objects and updated TAMS but not updated
// the prev bitmap.
if (G1VerifyBitmaps) {
- ((CMBitMap*) concurrent_mark()->prevMarkBitMap())->clearAll();
+ ((G1CMBitMap*) concurrent_mark()->prevMarkBitMap())->clearAll();
}
- check_bitmaps("Full GC End");
+ _verifier->check_bitmaps("Full GC End");
// Start a new incremental collection set for the next pause
assert(g1_policy()->collection_set() == NULL, "must be");
@@ -1441,15 +1444,15 @@
g1mm()->update_sizes();
gc_epilogue(true);
+
+ heap_transition.print();
+
+ print_heap_after_gc();
+ trace_heap_after_gc(gc_tracer);
+
+ post_full_gc_dump(gc_timer);
}
- g1_policy()->print_detailed_heap_transition();
-
- print_heap_after_gc();
- trace_heap_after_gc(gc_tracer);
-
- post_full_gc_dump(gc_timer);
-
gc_timer->register_gc_end();
gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
}
@@ -1639,7 +1642,7 @@
HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size, AllocationContext_t context) {
assert_at_safepoint(true /* should_be_vm_thread */);
- verify_region_sets_optional();
+ _verifier->verify_region_sets_optional();
size_t expand_bytes = MAX2(word_size * HeapWordSize, MinHeapDeltaBytes);
log_debug(gc, ergo, heap)("Attempt heap expansion (allocation request failed). Allocation request: " SIZE_FORMAT "B",
@@ -1648,7 +1651,7 @@
if (expand(expand_bytes)) {
_hrm.verify_optional();
- verify_region_sets_optional();
+ _verifier->verify_region_sets_optional();
return attempt_allocation_at_safepoint(word_size,
context,
false /* expect_null_mutator_alloc_region */);
@@ -1717,7 +1720,7 @@
}
void G1CollectedHeap::shrink(size_t shrink_bytes) {
- verify_region_sets_optional();
+ _verifier->verify_region_sets_optional();
// We should only reach here at the end of a Full GC which means we
// should not not be holding to any GC alloc regions. The method
@@ -1732,7 +1735,7 @@
rebuild_region_sets(true /* free_list_only */);
_hrm.verify_optional();
- verify_region_sets_optional();
+ _verifier->verify_region_sets_optional();
}
// Public methods.
@@ -1778,6 +1781,7 @@
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
_workers->initialize_workers();
+ _verifier = new G1HeapVerifier(this);
_allocator = G1Allocator::create_allocator(this);
_humongous_object_threshold_in_words = humongous_threshold_for(HeapRegion::GrainWords);
@@ -1920,11 +1924,11 @@
G1CardCounts::compute_size(g1_rs.size() / HeapWordSize),
G1CardCounts::heap_map_factor());
- size_t bitmap_size = CMBitMap::compute_size(g1_rs.size());
+ size_t bitmap_size = G1CMBitMap::compute_size(g1_rs.size());
G1RegionToSpaceMapper* prev_bitmap_storage =
- create_aux_memory_mapper("Prev Bitmap", bitmap_size, CMBitMap::heap_map_factor());
+ create_aux_memory_mapper("Prev Bitmap", bitmap_size, G1CMBitMap::heap_map_factor());
G1RegionToSpaceMapper* next_bitmap_storage =
- create_aux_memory_mapper("Next Bitmap", bitmap_size, CMBitMap::heap_map_factor());
+ create_aux_memory_mapper("Next Bitmap", bitmap_size, G1CMBitMap::heap_map_factor());
_hrm.initialize(heap_storage, prev_bitmap_storage, next_bitmap_storage, bot_storage, cardtable_storage, card_counts_storage);
g1_barrier_set()->initialize(cardtable_storage);
@@ -1956,11 +1960,11 @@
_humongous_reclaim_candidates.initialize(start, end, granularity);
}
- // Create the ConcurrentMark data structure and thread.
+ // Create the G1ConcurrentMark data structure and thread.
// (Must do this late, so that "max_regions" is defined.)
- _cm = new ConcurrentMark(this, prev_bitmap_storage, next_bitmap_storage);
+ _cm = new G1ConcurrentMark(this, prev_bitmap_storage, next_bitmap_storage);
if (_cm == NULL || !_cm->completed_initialization()) {
- vm_shutdown_during_initialization("Could not create/initialize ConcurrentMark");
+ vm_shutdown_during_initialization("Could not create/initialize G1ConcurrentMark");
return JNI_ENOMEM;
}
_cmThread = _cm->cmThread();
@@ -2667,452 +2671,11 @@
}
void G1CollectedHeap::prepare_for_verify() {
- if (SafepointSynchronize::is_at_safepoint() || ! UseTLAB) {
- ensure_parsability(false);
- }
- g1_rem_set()->prepare_for_verify();
-}
-
-bool G1CollectedHeap::allocated_since_marking(oop obj, HeapRegion* hr,
- VerifyOption vo) {
- switch (vo) {
- case VerifyOption_G1UsePrevMarking:
- return hr->obj_allocated_since_prev_marking(obj);
- case VerifyOption_G1UseNextMarking:
- return hr->obj_allocated_since_next_marking(obj);
- case VerifyOption_G1UseMarkWord:
- return false;
- default:
- ShouldNotReachHere();
- }
- return false; // keep some compilers happy
-}
-
-HeapWord* G1CollectedHeap::top_at_mark_start(HeapRegion* hr, VerifyOption vo) {
- switch (vo) {
- case VerifyOption_G1UsePrevMarking: return hr->prev_top_at_mark_start();
- case VerifyOption_G1UseNextMarking: return hr->next_top_at_mark_start();
- case VerifyOption_G1UseMarkWord: return NULL;
- default: ShouldNotReachHere();
- }
- return NULL; // keep some compilers happy
-}
-
-bool G1CollectedHeap::is_marked(oop obj, VerifyOption vo) {
- switch (vo) {
- case VerifyOption_G1UsePrevMarking: return isMarkedPrev(obj);
- case VerifyOption_G1UseNextMarking: return isMarkedNext(obj);
- case VerifyOption_G1UseMarkWord: return obj->is_gc_marked();
- default: ShouldNotReachHere();
- }
- return false; // keep some compilers happy
-}
-
-const char* G1CollectedHeap::top_at_mark_start_str(VerifyOption vo) {
- switch (vo) {
- case VerifyOption_G1UsePrevMarking: return "PTAMS";
- case VerifyOption_G1UseNextMarking: return "NTAMS";
- case VerifyOption_G1UseMarkWord: return "NONE";
- default: ShouldNotReachHere();
- }
- return NULL; // keep some compilers happy
+ _verifier->prepare_for_verify();
}
-class VerifyRootsClosure: public OopClosure {
-private:
- G1CollectedHeap* _g1h;
- VerifyOption _vo;
- bool _failures;
-public:
- // _vo == UsePrevMarking -> use "prev" marking information,
- // _vo == UseNextMarking -> use "next" marking information,
- // _vo == UseMarkWord -> use mark word from object header.
- VerifyRootsClosure(VerifyOption vo) :
- _g1h(G1CollectedHeap::heap()),
- _vo(vo),
- _failures(false) { }
-
- bool failures() { return _failures; }
-
- template <class T> void do_oop_nv(T* p) {
- T heap_oop = oopDesc::load_heap_oop(p);
- if (!oopDesc::is_null(heap_oop)) {
- oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
- if (_g1h->is_obj_dead_cond(obj, _vo)) {
- LogHandle(gc, verify) log;
- log.info("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj));
- if (_vo == VerifyOption_G1UseMarkWord) {
- log.info(" Mark word: " PTR_FORMAT, p2i(obj->mark()));
- }
- ResourceMark rm;
- obj->print_on(log.info_stream());
- _failures = true;
- }
- }
- }
-
- void do_oop(oop* p) { do_oop_nv(p); }
- void do_oop(narrowOop* p) { do_oop_nv(p); }
-};
-
-class G1VerifyCodeRootOopClosure: public OopClosure {
- G1CollectedHeap* _g1h;
- OopClosure* _root_cl;
- nmethod* _nm;
- VerifyOption _vo;
- bool _failures;
-
- template <class T> void do_oop_work(T* p) {
- // First verify that this root is live
- _root_cl->do_oop(p);
-
- if (!G1VerifyHeapRegionCodeRoots) {
- // We're not verifying the code roots attached to heap region.
- return;
- }
-
- // Don't check the code roots during marking verification in a full GC
- if (_vo == VerifyOption_G1UseMarkWord) {
- return;
- }
-
- // Now verify that the current nmethod (which contains p) is
- // in the code root list of the heap region containing the
- // object referenced by p.
-
- T heap_oop = oopDesc::load_heap_oop(p);
- if (!oopDesc::is_null(heap_oop)) {
- oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
-
- // Now fetch the region containing the object
- HeapRegion* hr = _g1h->heap_region_containing(obj);
- HeapRegionRemSet* hrrs = hr->rem_set();
- // Verify that the strong code root list for this region
- // contains the nmethod
- if (!hrrs->strong_code_roots_list_contains(_nm)) {
- log_info(gc, verify)("Code root location " PTR_FORMAT " "
- "from nmethod " PTR_FORMAT " not in strong "
- "code roots for region [" PTR_FORMAT "," PTR_FORMAT ")",
- p2i(p), p2i(_nm), p2i(hr->bottom()), p2i(hr->end()));
- _failures = true;
- }
- }
- }
-
-public:
- G1VerifyCodeRootOopClosure(G1CollectedHeap* g1h, OopClosure* root_cl, VerifyOption vo):
- _g1h(g1h), _root_cl(root_cl), _vo(vo), _nm(NULL), _failures(false) {}
-
- void do_oop(oop* p) { do_oop_work(p); }
- void do_oop(narrowOop* p) { do_oop_work(p); }
-
- void set_nmethod(nmethod* nm) { _nm = nm; }
- bool failures() { return _failures; }
-};
-
-class G1VerifyCodeRootBlobClosure: public CodeBlobClosure {
- G1VerifyCodeRootOopClosure* _oop_cl;
-
-public:
- G1VerifyCodeRootBlobClosure(G1VerifyCodeRootOopClosure* oop_cl):
- _oop_cl(oop_cl) {}
-
- void do_code_blob(CodeBlob* cb) {
- nmethod* nm = cb->as_nmethod_or_null();
- if (nm != NULL) {
- _oop_cl->set_nmethod(nm);
- nm->oops_do(_oop_cl);
- }
- }
-};
-
-class YoungRefCounterClosure : public OopClosure {
- G1CollectedHeap* _g1h;
- int _count;
- public:
- YoungRefCounterClosure(G1CollectedHeap* g1h) : _g1h(g1h), _count(0) {}
- void do_oop(oop* p) { if (_g1h->is_in_young(*p)) { _count++; } }
- void do_oop(narrowOop* p) { ShouldNotReachHere(); }
-
- int count() { return _count; }
- void reset_count() { _count = 0; };
-};
-
-class VerifyKlassClosure: public KlassClosure {
- YoungRefCounterClosure _young_ref_counter_closure;
- OopClosure *_oop_closure;
- public:
- VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {}
- void do_klass(Klass* k) {
- k->oops_do(_oop_closure);
-
- _young_ref_counter_closure.reset_count();
- k->oops_do(&_young_ref_counter_closure);
- if (_young_ref_counter_closure.count() > 0) {
- guarantee(k->has_modified_oops(), "Klass " PTR_FORMAT ", has young refs but is not dirty.", p2i(k));
- }
- }
-};
-
-class VerifyLivenessOopClosure: public OopClosure {
- G1CollectedHeap* _g1h;
- VerifyOption _vo;
-public:
- VerifyLivenessOopClosure(G1CollectedHeap* g1h, VerifyOption vo):
- _g1h(g1h), _vo(vo)
- { }
- void do_oop(narrowOop *p) { do_oop_work(p); }
- void do_oop( oop *p) { do_oop_work(p); }
-
- template <class T> void do_oop_work(T *p) {
- oop obj = oopDesc::load_decode_heap_oop(p);
- guarantee(obj == NULL || !_g1h->is_obj_dead_cond(obj, _vo),
- "Dead object referenced by a not dead object");
- }
-};
-
-class VerifyObjsInRegionClosure: public ObjectClosure {
-private:
- G1CollectedHeap* _g1h;
- size_t _live_bytes;
- HeapRegion *_hr;
- VerifyOption _vo;
-public:
- // _vo == UsePrevMarking -> use "prev" marking information,
- // _vo == UseNextMarking -> use "next" marking information,
- // _vo == UseMarkWord -> use mark word from object header.
- VerifyObjsInRegionClosure(HeapRegion *hr, VerifyOption vo)
- : _live_bytes(0), _hr(hr), _vo(vo) {
- _g1h = G1CollectedHeap::heap();
- }
- void do_object(oop o) {
- VerifyLivenessOopClosure isLive(_g1h, _vo);
- assert(o != NULL, "Huh?");
- if (!_g1h->is_obj_dead_cond(o, _vo)) {
- // If the object is alive according to the mark word,
- // then verify that the marking information agrees.
- // Note we can't verify the contra-positive of the
- // above: if the object is dead (according to the mark
- // word), it may not be marked, or may have been marked
- // but has since became dead, or may have been allocated
- // since the last marking.
- if (_vo == VerifyOption_G1UseMarkWord) {
- guarantee(!_g1h->is_obj_dead(o), "mark word and concurrent mark mismatch");
- }
-
- o->oop_iterate_no_header(&isLive);
- if (!_hr->obj_allocated_since_prev_marking(o)) {
- size_t obj_size = o->size(); // Make sure we don't overflow
- _live_bytes += (obj_size * HeapWordSize);
- }
- }
- }
- size_t live_bytes() { return _live_bytes; }
-};
-
-class VerifyArchiveOopClosure: public OopClosure {
-public:
- VerifyArchiveOopClosure(HeapRegion *hr) { }
- void do_oop(narrowOop *p) { do_oop_work(p); }
- void do_oop( oop *p) { do_oop_work(p); }
-
- template <class T> void do_oop_work(T *p) {
- oop obj = oopDesc::load_decode_heap_oop(p);
- guarantee(obj == NULL || G1MarkSweep::in_archive_range(obj),
- "Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT,
- p2i(p), p2i(obj));
- }
-};
-
-class VerifyArchiveRegionClosure: public ObjectClosure {
-public:
- VerifyArchiveRegionClosure(HeapRegion *hr) { }
- // Verify that all object pointers are to archive regions.
- void do_object(oop o) {
- VerifyArchiveOopClosure checkOop(NULL);
- assert(o != NULL, "Should not be here for NULL oops");
- o->oop_iterate_no_header(&checkOop);
- }
-};
-
-class VerifyRegionClosure: public HeapRegionClosure {
-private:
- bool _par;
- VerifyOption _vo;
- bool _failures;
-public:
- // _vo == UsePrevMarking -> use "prev" marking information,
- // _vo == UseNextMarking -> use "next" marking information,
- // _vo == UseMarkWord -> use mark word from object header.
- VerifyRegionClosure(bool par, VerifyOption vo)
- : _par(par),
- _vo(vo),
- _failures(false) {}
-
- bool failures() {
- return _failures;
- }
-
- bool doHeapRegion(HeapRegion* r) {
- // For archive regions, verify there are no heap pointers to
- // non-pinned regions. For all others, verify liveness info.
- if (r->is_archive()) {
- VerifyArchiveRegionClosure verify_oop_pointers(r);
- r->object_iterate(&verify_oop_pointers);
- return true;
- }
- if (!r->is_continues_humongous()) {
- bool failures = false;
- r->verify(_vo, &failures);
- if (failures) {
- _failures = true;
- } else if (!r->is_starts_humongous()) {
- VerifyObjsInRegionClosure not_dead_yet_cl(r, _vo);
- r->object_iterate(¬_dead_yet_cl);
- if (_vo != VerifyOption_G1UseNextMarking) {
- if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) {
- log_info(gc, verify)("[" PTR_FORMAT "," PTR_FORMAT "] max_live_bytes " SIZE_FORMAT " < calculated " SIZE_FORMAT,
- p2i(r->bottom()), p2i(r->end()), r->max_live_bytes(), not_dead_yet_cl.live_bytes());
- _failures = true;
- }
- } else {
- // When vo == UseNextMarking we cannot currently do a sanity
- // check on the live bytes as the calculation has not been
- // finalized yet.
- }
- }
- }
- return false; // stop the region iteration if we hit a failure
- }
-};
-
-// This is the task used for parallel verification of the heap regions
-
-class G1ParVerifyTask: public AbstractGangTask {
-private:
- G1CollectedHeap* _g1h;
- VerifyOption _vo;
- bool _failures;
- HeapRegionClaimer _hrclaimer;
-
-public:
- // _vo == UsePrevMarking -> use "prev" marking information,
- // _vo == UseNextMarking -> use "next" marking information,
- // _vo == UseMarkWord -> use mark word from object header.
- G1ParVerifyTask(G1CollectedHeap* g1h, VerifyOption vo) :
- AbstractGangTask("Parallel verify task"),
- _g1h(g1h),
- _vo(vo),
- _failures(false),
- _hrclaimer(g1h->workers()->active_workers()) {}
-
- bool failures() {
- return _failures;
- }
-
- void work(uint worker_id) {
- HandleMark hm;
- VerifyRegionClosure blk(true, _vo);
- _g1h->heap_region_par_iterate(&blk, worker_id, &_hrclaimer);
- if (blk.failures()) {
- _failures = true;
- }
- }
-};
-
void G1CollectedHeap::verify(VerifyOption vo) {
- if (!SafepointSynchronize::is_at_safepoint()) {
- log_info(gc, verify)("Skipping verification. Not at safepoint.");
- }
-
- assert(Thread::current()->is_VM_thread(),
- "Expected to be executed serially by the VM thread at this point");
-
- log_debug(gc, verify)("Roots");
- VerifyRootsClosure rootsCl(vo);
- VerifyKlassClosure klassCl(this, &rootsCl);
- CLDToKlassAndOopClosure cldCl(&klassCl, &rootsCl, false);
-
- // We apply the relevant closures to all the oops in the
- // system dictionary, class loader data graph, the string table
- // and the nmethods in the code cache.
- G1VerifyCodeRootOopClosure codeRootsCl(this, &rootsCl, vo);
- G1VerifyCodeRootBlobClosure blobsCl(&codeRootsCl);
-
- {
- G1RootProcessor root_processor(this, 1);
- root_processor.process_all_roots(&rootsCl,
- &cldCl,
- &blobsCl);
- }
-
- bool failures = rootsCl.failures() || codeRootsCl.failures();
-
- if (vo != VerifyOption_G1UseMarkWord) {
- // If we're verifying during a full GC then the region sets
- // will have been torn down at the start of the GC. Therefore
- // verifying the region sets will fail. So we only verify
- // the region sets when not in a full GC.
- log_debug(gc, verify)("HeapRegionSets");
- verify_region_sets();
- }
-
- log_debug(gc, verify)("HeapRegions");
- if (GCParallelVerificationEnabled && ParallelGCThreads > 1) {
-
- G1ParVerifyTask task(this, vo);
- workers()->run_task(&task);
- if (task.failures()) {
- failures = true;
- }
-
- } else {
- VerifyRegionClosure blk(false, vo);
- heap_region_iterate(&blk);
- if (blk.failures()) {
- failures = true;
- }
- }
-
- if (G1StringDedup::is_enabled()) {
- log_debug(gc, verify)("StrDedup");
- G1StringDedup::verify();
- }
-
- if (failures) {
- log_info(gc, verify)("Heap after failed verification:");
- // It helps to have the per-region information in the output to
- // help us track down what went wrong. This is why we call
- // print_extended_on() instead of print_on().
- LogHandle(gc, verify) log;
- ResourceMark rm;
- print_extended_on(log.info_stream());
- }
- guarantee(!failures, "there should not have been any failures");
-}
-
-double G1CollectedHeap::verify(bool guard, const char* msg) {
- double verify_time_ms = 0.0;
-
- if (guard && total_collections() >= VerifyGCStartAt) {
- double verify_start = os::elapsedTime();
- HandleMark hm; // Discard invalid handles created during verification
- prepare_for_verify();
- Universe::verify(VerifyOption_G1UsePrevMarking, msg);
- verify_time_ms = (os::elapsedTime() - verify_start) * 1000;
- }
-
- return verify_time_ms;
-}
-
-void G1CollectedHeap::verify_before_gc() {
- double verify_time_ms = verify(VerifyBeforeGC, "Before GC");
- g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms);
-}
-
-void G1CollectedHeap::verify_after_gc() {
- double verify_time_ms = verify(VerifyAfterGC, "After GC");
- g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms);
+ _verifier->verify(vo);
}
class PrintRegionClosure: public HeapRegionClosure {
@@ -3580,7 +3143,7 @@
}
void G1CollectedHeap::print_taskqueue_stats() const {
- if (!develop_log_is_enabled(Trace, gc, task, stats)) {
+ if (!log_develop_is_enabled(Trace, gc, task, stats)) {
return;
}
LogHandle(gc, task, stats) log;
@@ -3608,18 +3171,6 @@
}
#endif // TASKQUEUE_STATS
-void G1CollectedHeap::log_gc_footer(jlong pause_time_counter) {
- if (evacuation_failed()) {
- log_info(gc)("To-space exhausted");
- }
-
- double pause_time_ms = TimeHelper::counter_to_millis(pause_time_counter);
- g1_policy()->print_phases(pause_time_ms);
-
- g1_policy()->print_detailed_heap_transition();
-}
-
-
void G1CollectedHeap::wait_for_root_region_scanning() {
double scan_wait_start = os::elapsedTime();
// We have to wait until the CM threads finish scanning the
@@ -3657,8 +3208,8 @@
print_heap_before_gc();
trace_heap_before_gc(_gc_tracer_stw);
- verify_region_sets_optional();
- verify_dirty_young_regions();
+ _verifier->verify_region_sets_optional();
+ _verifier->verify_dirty_young_regions();
// This call will decide whether this pause is an initial-mark
// pause. If it is, during_initial_mark_pause() will return true
@@ -3706,7 +3257,6 @@
}
GCTraceTime(Info, gc) tm(gc_string, NULL, gc_cause(), true);
- jlong pause_start_counter = os::elapsed_counter();
g1_policy()->note_gc_start(active_workers);
TraceCollectorStats tcs(g1mm()->incremental_collection_counters());
@@ -3722,6 +3272,9 @@
append_secondary_free_list_if_not_empty_with_lock();
}
+ G1HeapTransition heap_transition(this);
+ size_t heap_used_bytes_before_gc = used();
+
assert(check_young_list_well_formed(), "young list should be well formed");
// Don't dynamically change the number of GC threads this early. A value of
@@ -3741,9 +3294,9 @@
heap_region_iterate(&v_cl);
}
- verify_before_gc();
-
- check_bitmaps("GC Start");
+ _verifier->verify_before_gc();
+
+ _verifier->check_bitmaps("GC Start");
#if defined(COMPILER2) || INCLUDE_JVMCI
DerivedPointerTable::clear();
@@ -3801,7 +3354,7 @@
register_humongous_regions_with_cset();
- assert(check_cset_fast_test(), "Inconsistency in the InCSetState table.");
+ assert(_verifier->check_cset_fast_test(), "Inconsistency in the InCSetState table.");
_cm->note_start_of_gc();
// We call this after finalize_cset() to
@@ -3915,7 +3468,7 @@
double sample_end_time_sec = os::elapsedTime();
double pause_time_ms = (sample_end_time_sec - sample_start_time_sec) * MILLIUNITS;
size_t total_cards_scanned = per_thread_states.total_cards_scanned();
- g1_policy()->record_collection_pause_end(pause_time_ms, total_cards_scanned);
+ g1_policy()->record_collection_pause_end(pause_time_ms, total_cards_scanned, heap_used_bytes_before_gc);
evacuation_info.set_collectionset_used_before(g1_policy()->collection_set_bytes_used_before());
evacuation_info.set_bytes_copied(g1_policy()->bytes_copied_during_gc());
@@ -3951,8 +3504,8 @@
heap_region_iterate(&v_cl);
}
- verify_after_gc();
- check_bitmaps("GC End");
+ _verifier->verify_after_gc();
+ _verifier->check_bitmaps("GC End");
assert(!ref_processor_stw()->discovery_enabled(), "Postcondition");
ref_processor_stw()->verify_no_references_recorded();
@@ -3968,7 +3521,12 @@
}
// Print the remainder of the GC log output.
- log_gc_footer(os::elapsed_counter() - pause_start_counter);
+ if (evacuation_failed()) {
+ log_info(gc)("To-space exhausted");
+ }
+
+ g1_policy()->print_phases();
+ heap_transition.print();
// It is not yet to safe to tell the concurrent mark to
// start as we have some optional output below. We don't want the
@@ -3976,7 +3534,7 @@
// logging output either.
_hrm.verify_optional();
- verify_region_sets_optional();
+ _verifier->verify_region_sets_optional();
TASKQUEUE_STATS_ONLY(print_taskqueue_stats());
TASKQUEUE_STATS_ONLY(reset_taskqueue_stats());
@@ -5245,197 +4803,6 @@
}
};
-#ifndef PRODUCT
-class G1VerifyCardTableCleanup: public HeapRegionClosure {
- G1CollectedHeap* _g1h;
- G1SATBCardTableModRefBS* _ct_bs;
-public:
- G1VerifyCardTableCleanup(G1CollectedHeap* g1h, G1SATBCardTableModRefBS* ct_bs)
- : _g1h(g1h), _ct_bs(ct_bs) { }
- virtual bool doHeapRegion(HeapRegion* r) {
- if (r->is_survivor()) {
- _g1h->verify_dirty_region(r);
- } else {
- _g1h->verify_not_dirty_region(r);
- }
- return false;
- }
-};
-
-void G1CollectedHeap::verify_not_dirty_region(HeapRegion* hr) {
- // All of the region should be clean.
- G1SATBCardTableModRefBS* ct_bs = g1_barrier_set();
- MemRegion mr(hr->bottom(), hr->end());
- ct_bs->verify_not_dirty_region(mr);
-}
-
-void G1CollectedHeap::verify_dirty_region(HeapRegion* hr) {
- // We cannot guarantee that [bottom(),end()] is dirty. Threads
- // dirty allocated blocks as they allocate them. The thread that
- // retires each region and replaces it with a new one will do a
- // maximal allocation to fill in [pre_dummy_top(),end()] but will
- // not dirty that area (one less thing to have to do while holding
- // a lock). So we can only verify that [bottom(),pre_dummy_top()]
- // is dirty.
- G1SATBCardTableModRefBS* ct_bs = g1_barrier_set();
- MemRegion mr(hr->bottom(), hr->pre_dummy_top());
- if (hr->is_young()) {
- ct_bs->verify_g1_young_region(mr);
- } else {
- ct_bs->verify_dirty_region(mr);
- }
-}
-
-void G1CollectedHeap::verify_dirty_young_list(HeapRegion* head) {
- G1SATBCardTableModRefBS* ct_bs = g1_barrier_set();
- for (HeapRegion* hr = head; hr != NULL; hr = hr->get_next_young_region()) {
- verify_dirty_region(hr);
- }
-}
-
-void G1CollectedHeap::verify_dirty_young_regions() {
- verify_dirty_young_list(_young_list->first_region());
-}
-
-bool G1CollectedHeap::verify_no_bits_over_tams(const char* bitmap_name, CMBitMapRO* bitmap,
- HeapWord* tams, HeapWord* end) {
- guarantee(tams <= end,
- "tams: " PTR_FORMAT " end: " PTR_FORMAT, p2i(tams), p2i(end));
- HeapWord* result = bitmap->getNextMarkedWordAddress(tams, end);
- if (result < end) {
- log_info(gc, verify)("## wrong marked address on %s bitmap: " PTR_FORMAT, bitmap_name, p2i(result));
- log_info(gc, verify)("## %s tams: " PTR_FORMAT " end: " PTR_FORMAT, bitmap_name, p2i(tams), p2i(end));
- return false;
- }
- return true;
-}
-
-bool G1CollectedHeap::verify_bitmaps(const char* caller, HeapRegion* hr) {
- CMBitMapRO* prev_bitmap = concurrent_mark()->prevMarkBitMap();
- CMBitMapRO* next_bitmap = (CMBitMapRO*) concurrent_mark()->nextMarkBitMap();
-
- HeapWord* bottom = hr->bottom();
- HeapWord* ptams = hr->prev_top_at_mark_start();
- HeapWord* ntams = hr->next_top_at_mark_start();
- HeapWord* end = hr->end();
-
- bool res_p = verify_no_bits_over_tams("prev", prev_bitmap, ptams, end);
-
- bool res_n = true;
- // We reset mark_in_progress() before we reset _cmThread->in_progress() and in this window
- // we do the clearing of the next bitmap concurrently. Thus, we can not verify the bitmap
- // if we happen to be in that state.
- if (collector_state()->mark_in_progress() || !_cmThread->in_progress()) {
- res_n = verify_no_bits_over_tams("next", next_bitmap, ntams, end);
- }
- if (!res_p || !res_n) {
- log_info(gc, verify)("#### Bitmap verification failed for " HR_FORMAT, HR_FORMAT_PARAMS(hr));
- log_info(gc, verify)("#### Caller: %s", caller);
- return false;
- }
- return true;
-}
-
-void G1CollectedHeap::check_bitmaps(const char* caller, HeapRegion* hr) {
- if (!G1VerifyBitmaps) return;
-
- guarantee(verify_bitmaps(caller, hr), "bitmap verification");
-}
-
-class G1VerifyBitmapClosure : public HeapRegionClosure {
-private:
- const char* _caller;
- G1CollectedHeap* _g1h;
- bool _failures;
-
-public:
- G1VerifyBitmapClosure(const char* caller, G1CollectedHeap* g1h) :
- _caller(caller), _g1h(g1h), _failures(false) { }
-
- bool failures() { return _failures; }
-
- virtual bool doHeapRegion(HeapRegion* hr) {
- bool result = _g1h->verify_bitmaps(_caller, hr);
- if (!result) {
- _failures = true;
- }
- return false;
- }
-};
-
-void G1CollectedHeap::check_bitmaps(const char* caller) {
- if (!G1VerifyBitmaps) return;
-
- G1VerifyBitmapClosure cl(caller, this);
- heap_region_iterate(&cl);
- guarantee(!cl.failures(), "bitmap verification");
-}
-
-class G1CheckCSetFastTableClosure : public HeapRegionClosure {
- private:
- bool _failures;
- public:
- G1CheckCSetFastTableClosure() : HeapRegionClosure(), _failures(false) { }
-
- virtual bool doHeapRegion(HeapRegion* hr) {
- uint i = hr->hrm_index();
- InCSetState cset_state = (InCSetState) G1CollectedHeap::heap()->_in_cset_fast_test.get_by_index(i);
- if (hr->is_humongous()) {
- if (hr->in_collection_set()) {
- log_info(gc, verify)("## humongous region %u in CSet", i);
- _failures = true;
- return true;
- }
- if (cset_state.is_in_cset()) {
- log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i);
- _failures = true;
- return true;
- }
- if (hr->is_continues_humongous() && cset_state.is_humongous()) {
- log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i);
- _failures = true;
- return true;
- }
- } else {
- if (cset_state.is_humongous()) {
- log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i);
- _failures = true;
- return true;
- }
- if (hr->in_collection_set() != cset_state.is_in_cset()) {
- log_info(gc, verify)("## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
- hr->in_collection_set(), cset_state.value(), i);
- _failures = true;
- return true;
- }
- if (cset_state.is_in_cset()) {
- if (hr->is_young() != (cset_state.is_young())) {
- log_info(gc, verify)("## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
- hr->is_young(), cset_state.value(), i);
- _failures = true;
- return true;
- }
- if (hr->is_old() != (cset_state.is_old())) {
- log_info(gc, verify)("## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
- hr->is_old(), cset_state.value(), i);
- _failures = true;
- return true;
- }
- }
- }
- return false;
- }
-
- bool failures() const { return _failures; }
-};
-
-bool G1CollectedHeap::check_cset_fast_test() {
- G1CheckCSetFastTableClosure cl;
- _hrm.iterate(&cl);
- return !cl.failures();
-}
-#endif // PRODUCT
-
class G1ParScrubRemSetTask: public AbstractGangTask {
protected:
G1RemSet* _g1rs;
@@ -5473,10 +4840,7 @@
workers()->run_task(&cleanup_task);
#ifndef PRODUCT
- if (G1VerifyCTCleanup || VerifyAfterGC) {
- G1VerifyCardTableCleanup cleanup_verifier(this, ct_bs);
- heap_region_iterate(&cleanup_verifier);
- }
+ _verifier->verify_card_table_cleanup();
#endif
}
@@ -5628,7 +4992,7 @@
G1CollectedHeap* g1h = G1CollectedHeap::heap();
oop obj = (oop)r->bottom();
- CMBitMap* next_bitmap = g1h->concurrent_mark()->nextMarkBitMap();
+ G1CMBitMap* next_bitmap = g1h->concurrent_mark()->nextMarkBitMap();
// The following checks whether the humongous object is live are sufficient.
// The main additional check (in addition to having a reference from the roots
@@ -5998,7 +5362,7 @@
if (new_alloc_region != NULL) {
set_region_short_lived_locked(new_alloc_region);
_hr_printer.alloc(new_alloc_region, young_list_full);
- check_bitmaps("Mutator Region Allocation", new_alloc_region);
+ _verifier->check_bitmaps("Mutator Region Allocation", new_alloc_region);
return new_alloc_region;
}
}
@@ -6038,10 +5402,10 @@
new_alloc_region->record_timestamp();
if (is_survivor) {
new_alloc_region->set_survivor();
- check_bitmaps("Survivor Region Allocation", new_alloc_region);
+ _verifier->check_bitmaps("Survivor Region Allocation", new_alloc_region);
} else {
new_alloc_region->set_old();
- check_bitmaps("Old Region Allocation", new_alloc_region);
+ _verifier->check_bitmaps("Old Region Allocation", new_alloc_region);
}
_hr_printer.alloc(new_alloc_region);
bool during_im = collector_state()->during_initial_mark_pause();
@@ -6081,93 +5445,6 @@
return NULL;
}
-// Heap region set verification
-
-class VerifyRegionListsClosure : public HeapRegionClosure {
-private:
- HeapRegionSet* _old_set;
- HeapRegionSet* _humongous_set;
- HeapRegionManager* _hrm;
-
-public:
- uint _old_count;
- uint _humongous_count;
- uint _free_count;
-
- VerifyRegionListsClosure(HeapRegionSet* old_set,
- HeapRegionSet* humongous_set,
- HeapRegionManager* hrm) :
- _old_set(old_set), _humongous_set(humongous_set), _hrm(hrm),
- _old_count(), _humongous_count(), _free_count(){ }
-
- bool doHeapRegion(HeapRegion* hr) {
- if (hr->is_young()) {
- // TODO
- } else if (hr->is_humongous()) {
- assert(hr->containing_set() == _humongous_set, "Heap region %u is humongous but not in humongous set.", hr->hrm_index());
- _humongous_count++;
- } else if (hr->is_empty()) {
- assert(_hrm->is_free(hr), "Heap region %u is empty but not on the free list.", hr->hrm_index());
- _free_count++;
- } else if (hr->is_old()) {
- assert(hr->containing_set() == _old_set, "Heap region %u is old but not in the old set.", hr->hrm_index());
- _old_count++;
- } else {
- // There are no other valid region types. Check for one invalid
- // one we can identify: pinned without old or humongous set.
- assert(!hr->is_pinned(), "Heap region %u is pinned but not old (archive) or humongous.", hr->hrm_index());
- ShouldNotReachHere();
- }
- return false;
- }
-
- void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionManager* free_list) {
- guarantee(old_set->length() == _old_count, "Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count);
- guarantee(humongous_set->length() == _humongous_count, "Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count);
- guarantee(free_list->num_free_regions() == _free_count, "Free list count mismatch. Expected %u, actual %u.", free_list->num_free_regions(), _free_count);
- }
-};
-
-void G1CollectedHeap::verify_region_sets() {
- assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */);
-
- // First, check the explicit lists.
- _hrm.verify();
- {
- // Given that a concurrent operation might be adding regions to
- // the secondary free list we have to take the lock before
- // verifying it.
- MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag);
- _secondary_free_list.verify_list();
- }
-
- // If a concurrent region freeing operation is in progress it will
- // be difficult to correctly attributed any free regions we come
- // across to the correct free list given that they might belong to
- // one of several (free_list, secondary_free_list, any local lists,
- // etc.). So, if that's the case we will skip the rest of the
- // verification operation. Alternatively, waiting for the concurrent
- // operation to complete will have a non-trivial effect on the GC's
- // operation (no concurrent operation will last longer than the
- // interval between two calls to verification) and it might hide
- // any issues that we would like to catch during testing.
- if (free_regions_coming()) {
- return;
- }
-
- // Make sure we append the secondary_free_list on the free_list so
- // that all free regions we will come across can be safely
- // attributed to the free_list.
- append_secondary_free_list_if_not_empty_with_lock();
-
- // Finally, make sure that the region accounting in the lists is
- // consistent with what we see in the heap.
-
- VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_hrm);
- heap_region_iterate(&cl);
- cl.verify_counts(&_old_set, &_humongous_set, &_hrm);
-}
-
// Optimized nmethod scanning
class RegisterNMethodOopClosure: public OopClosure {
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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,11 +25,11 @@
#ifndef SHARE_VM_GC_G1_G1COLLECTEDHEAP_HPP
#define SHARE_VM_GC_G1_G1COLLECTEDHEAP_HPP
-#include "gc/g1/concurrentMark.hpp"
#include "gc/g1/evacuationInfo.hpp"
#include "gc/g1/g1AllocationContext.hpp"
#include "gc/g1/g1BiasedArray.hpp"
#include "gc/g1/g1CollectorState.hpp"
+#include "gc/g1/g1ConcurrentMark.hpp"
#include "gc/g1/g1HRPrinter.hpp"
#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1MonitoringSupport.hpp"
@@ -68,7 +68,7 @@
class G1CollectorPolicy;
class G1RemSet;
class HeapRegionRemSetIterator;
-class ConcurrentMark;
+class G1ConcurrentMark;
class ConcurrentMarkThread;
class ConcurrentG1Refine;
class ConcurrentGCTimer;
@@ -82,6 +82,7 @@
class WorkGang;
class G1Allocator;
class G1ArchiveAllocator;
+class G1HeapVerifier;
typedef OverflowTaskQueue<StarTask, mtGC> RefToScanQueue;
typedef GenericTaskQueueSet<RefToScanQueue, mtGC> RefToScanQueueSet;
@@ -118,6 +119,7 @@
friend class VMStructs;
friend class MutatorAllocRegion;
friend class G1GCAllocRegion;
+ friend class G1HeapVerifier;
// Closures used in implementation.
friend class G1ParScanThreadState;
@@ -181,6 +183,9 @@
// Manages all allocations with regions except humongous object allocations.
G1Allocator* _allocator;
+ // Manages all heap verification.
+ G1HeapVerifier* _verifier;
+
// Outside of GC pauses, the number of bytes used in all regions other
// than the current allocation region(s).
size_t _summary_bytes_used;
@@ -286,12 +291,6 @@
size_t size,
size_t translation_factor);
- double verify(bool guard, const char* msg);
- void verify_before_gc();
- void verify_after_gc();
-
- void log_gc_footer(jlong pause_time_counter);
-
void trace_heap(GCWhen::Type when, const GCTracer* tracer);
void process_weak_jni_handles();
@@ -527,6 +526,10 @@
return _allocator;
}
+ G1HeapVerifier* verifier() {
+ return _verifier;
+ }
+
G1MonitoringSupport* g1mm() {
assert(_g1mm != NULL, "should have been initialized");
return _g1mm;
@@ -768,7 +771,7 @@
void abandon_collection_set(HeapRegion* cs_head);
// The concurrent marker (and the thread it runs in.)
- ConcurrentMark* _cm;
+ G1ConcurrentMark* _cm;
ConcurrentMarkThread* _cmThread;
// The concurrent refiner.
@@ -1056,54 +1059,6 @@
// The number of regions that are not completely free.
uint num_used_regions() const { return num_regions() - num_free_regions(); }
- void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
- void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
- void verify_dirty_young_list(HeapRegion* head) PRODUCT_RETURN;
- void verify_dirty_young_regions() PRODUCT_RETURN;
-
-#ifndef PRODUCT
- // Make sure that the given bitmap has no marked objects in the
- // range [from,limit). If it does, print an error message and return
- // false. Otherwise, just return true. bitmap_name should be "prev"
- // or "next".
- bool verify_no_bits_over_tams(const char* bitmap_name, CMBitMapRO* bitmap,
- HeapWord* from, HeapWord* limit);
-
- // Verify that the prev / next bitmap range [tams,end) for the given
- // region has no marks. Return true if all is well, false if errors
- // are detected.
- bool verify_bitmaps(const char* caller, HeapRegion* hr);
-#endif // PRODUCT
-
- // If G1VerifyBitmaps is set, verify that the marking bitmaps for
- // the given region do not have any spurious marks. If errors are
- // detected, print appropriate error messages and crash.
- void check_bitmaps(const char* caller, HeapRegion* hr) PRODUCT_RETURN;
-
- // If G1VerifyBitmaps is set, verify that the marking bitmaps do not
- // have any spurious marks. If errors are detected, print
- // appropriate error messages and crash.
- void check_bitmaps(const char* caller) PRODUCT_RETURN;
-
- // Do sanity check on the contents of the in-cset fast test table.
- bool check_cset_fast_test() PRODUCT_RETURN_( return true; );
-
- // verify_region_sets() performs verification over the region
- // lists. It will be compiled in the product code to be used when
- // necessary (i.e., during heap verification).
- void verify_region_sets();
-
- // verify_region_sets_optional() is planted in the code for
- // list verification in non-product builds (and it can be enabled in
- // product builds by defining HEAP_REGION_SET_FORCE_VERIFY to be 1).
-#if HEAP_REGION_SET_FORCE_VERIFY
- void verify_region_sets_optional() {
- verify_region_sets();
- }
-#else // HEAP_REGION_SET_FORCE_VERIFY
- void verify_region_sets_optional() { }
-#endif // HEAP_REGION_SET_FORCE_VERIFY
-
#ifdef ASSERT
bool is_on_master_free_list(HeapRegion* hr) {
return _hrm.is_free(hr);
@@ -1425,12 +1380,7 @@
inline bool is_obj_ill(const oop obj) const;
- bool allocated_since_marking(oop obj, HeapRegion* hr, VerifyOption vo);
- HeapWord* top_at_mark_start(HeapRegion* hr, VerifyOption vo);
- bool is_marked(oop obj, VerifyOption vo);
- const char* top_at_mark_start_str(VerifyOption vo);
-
- ConcurrentMark* concurrent_mark() const { return _cm; }
+ G1ConcurrentMark* concurrent_mark() const { return _cm; }
// Refinement
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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,10 +25,10 @@
#ifndef SHARE_VM_GC_G1_G1COLLECTEDHEAP_INLINE_HPP
#define SHARE_VM_GC_G1_G1COLLECTEDHEAP_INLINE_HPP
-#include "gc/g1/concurrentMark.hpp"
#include "gc/g1/g1CollectedHeap.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
#include "gc/g1/g1CollectorState.hpp"
+#include "gc/g1/g1ConcurrentMark.hpp"
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
#include "gc/g1/heapRegionManager.inline.hpp"
#include "gc/g1/heapRegionSet.inline.hpp"
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -24,10 +24,10 @@
#include "precompiled.hpp"
#include "gc/g1/concurrentG1Refine.hpp"
-#include "gc/g1/concurrentMark.hpp"
#include "gc/g1/concurrentMarkThread.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
+#include "gc/g1/g1ConcurrentMark.hpp"
#include "gc/g1/g1IHOPControl.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
#include "gc/g1/heapRegion.inline.hpp"
@@ -117,15 +117,6 @@
_rs_lengths_prediction(0),
_max_survivor_regions(0),
- _eden_used_bytes_before_gc(0),
- _survivor_used_bytes_before_gc(0),
- _old_used_bytes_before_gc(0),
- _humongous_used_bytes_before_gc(0),
- _heap_used_bytes_before_gc(0),
- _metaspace_used_bytes_before_gc(0),
- _eden_capacity_bytes_before_gc(0),
- _heap_capacity_bytes_before_gc(0),
-
_eden_cset_region_length(0),
_survivor_cset_region_length(0),
_old_cset_region_length(0),
@@ -745,22 +736,6 @@
}
}
-HeapWord* G1CollectorPolicy::mem_allocate_work(size_t size,
- bool is_tlab,
- bool* gc_overhead_limit_was_exceeded) {
- guarantee(false, "Not using this policy feature yet.");
- return NULL;
-}
-
-// This method controls how a collector handles one or more
-// of its generations being fully allocated.
-HeapWord* G1CollectorPolicy::satisfy_failed_allocation(size_t size,
- bool is_tlab) {
- guarantee(false, "Not using this policy feature yet.");
- return NULL;
-}
-
-
#ifndef PRODUCT
bool G1CollectorPolicy::verify_young_ages() {
HeapRegion* head = _g1->young_list()->first_region();
@@ -809,7 +784,6 @@
void G1CollectorPolicy::record_full_collection_start() {
_full_collection_start_sec = os::elapsedTime();
- record_heap_size_info_at_start(true /* full */);
// Release the future to-space so that it is available for compaction into.
collector_state()->set_full_collection(true);
}
@@ -871,8 +845,6 @@
_trace_young_gen_time_data.record_start_collection(s_w_t_ms);
_stop_world_start = 0.0;
- record_heap_size_info_at_start(false /* full */);
-
phase_times()->record_cur_collection_start_sec(start_time_sec);
_pending_cards = _g1->pending_card_num();
@@ -987,7 +959,7 @@
// Anything below that is considered to be zero
#define MIN_TIMER_GRANULARITY 0.0000001
-void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t cards_scanned) {
+void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t cards_scanned, size_t heap_used_bytes_before_gc) {
double end_time_sec = os::elapsedTime();
size_t cur_used_bytes = _g1->used();
@@ -1138,7 +1110,7 @@
}
_rs_length_diff_seq->add((double) rs_length_diff);
- size_t freed_bytes = _heap_used_bytes_before_gc - cur_used_bytes;
+ size_t freed_bytes = heap_used_bytes_before_gc - cur_used_bytes;
size_t copied_bytes = _collection_set_bytes_used_before - freed_bytes;
double cost_per_byte_ms = 0.0;
@@ -1260,51 +1232,8 @@
_ihop_control->print();
}
-#define EXT_SIZE_FORMAT "%.1f%s"
-#define EXT_SIZE_PARAMS(bytes) \
- byte_size_in_proper_unit((double)(bytes)), \
- proper_unit_for_byte_size((bytes))
-
-void G1CollectorPolicy::record_heap_size_info_at_start(bool full) {
- YoungList* young_list = _g1->young_list();
- _eden_used_bytes_before_gc = young_list->eden_used_bytes();
- _survivor_used_bytes_before_gc = young_list->survivor_used_bytes();
- _heap_capacity_bytes_before_gc = _g1->capacity();
- _old_used_bytes_before_gc = _g1->old_regions_count() * HeapRegion::GrainBytes;
- _humongous_used_bytes_before_gc = _g1->humongous_regions_count() * HeapRegion::GrainBytes;
- _heap_used_bytes_before_gc = _g1->used();
- _eden_capacity_bytes_before_gc = (_young_list_target_length * HeapRegion::GrainBytes) - _survivor_used_bytes_before_gc;
- _metaspace_used_bytes_before_gc = MetaspaceAux::used_bytes();
-}
-
-void G1CollectorPolicy::print_detailed_heap_transition() const {
- YoungList* young_list = _g1->young_list();
-
- size_t eden_used_bytes_after_gc = young_list->eden_used_bytes();
- size_t survivor_used_bytes_after_gc = young_list->survivor_used_bytes();
- size_t heap_used_bytes_after_gc = _g1->used();
- size_t old_used_bytes_after_gc = _g1->old_regions_count() * HeapRegion::GrainBytes;
- size_t humongous_used_bytes_after_gc = _g1->humongous_regions_count() * HeapRegion::GrainBytes;
-
- size_t heap_capacity_bytes_after_gc = _g1->capacity();
- size_t eden_capacity_bytes_after_gc =
- (_young_list_target_length * HeapRegion::GrainBytes) - survivor_used_bytes_after_gc;
- size_t survivor_capacity_bytes_after_gc = _max_survivor_regions * HeapRegion::GrainBytes;
-
- log_info(gc, heap)("Eden: " SIZE_FORMAT "K->" SIZE_FORMAT "K(" SIZE_FORMAT "K)",
- _eden_used_bytes_before_gc / K, eden_used_bytes_after_gc /K, eden_capacity_bytes_after_gc /K);
- log_info(gc, heap)("Survivor: " SIZE_FORMAT "K->" SIZE_FORMAT "K(" SIZE_FORMAT "K)",
- _survivor_used_bytes_before_gc / K, survivor_used_bytes_after_gc /K, survivor_capacity_bytes_after_gc /K);
- log_info(gc, heap)("Old: " SIZE_FORMAT "K->" SIZE_FORMAT "K",
- _old_used_bytes_before_gc / K, old_used_bytes_after_gc /K);
- log_info(gc, heap)("Humongous: " SIZE_FORMAT "K->" SIZE_FORMAT "K",
- _humongous_used_bytes_before_gc / K, humongous_used_bytes_after_gc /K);
-
- MetaspaceAux::print_metaspace_change(_metaspace_used_bytes_before_gc);
-}
-
-void G1CollectorPolicy::print_phases(double pause_time_ms) {
- phase_times()->print(pause_time_ms);
+void G1CollectorPolicy::print_phases() {
+ phase_times()->print();
}
void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time,
@@ -2310,7 +2239,7 @@
// whether we added any apparently expensive regions or not, to
// avoid generating output per region.
log_debug(gc, ergo, cset)("Added expensive regions to CSet (old CSet region num not reached min)."
- "old %u regions, expensive: %u regions, min %u regions, remaining time: %1.2fms",
+ "old: %u regions, expensive: %u regions, min: %u regions, remaining time: %1.2fms",
old_cset_region_length(), expensive_region_num, min_old_cset_length, time_remaining_ms);
}
@@ -2319,7 +2248,7 @@
stop_incremental_cset_building();
- log_debug(gc, ergo, cset)("Finish choosing CSet. old %u regions, predicted old region time: %1.2fms, time remaining: %1.2f",
+ log_debug(gc, ergo, cset)("Finish choosing CSet. old: %u regions, predicted old region time: %1.2fms, time remaining: %1.2f",
old_cset_region_length(), predicted_old_time_ms, time_remaining_ms);
double non_young_end_time_sec = os::elapsedTime();
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -621,22 +621,13 @@
// Create jstat counters for the policy.
virtual void initialize_gc_policy_counters();
- virtual HeapWord* mem_allocate_work(size_t size,
- bool is_tlab,
- bool* gc_overhead_limit_was_exceeded);
-
- // This method controls how a collector handles one or more
- // of its generations being fully allocated.
- virtual HeapWord* satisfy_failed_allocation(size_t size,
- bool is_tlab);
-
bool need_to_start_conc_mark(const char* source, size_t alloc_word_size = 0);
bool about_to_start_mixed_phase() const;
// Record the start and end of an evacuation pause.
void record_collection_pause_start(double start_time_sec);
- void record_collection_pause_end(double pause_time_ms, size_t cards_scanned);
+ void record_collection_pause_end(double pause_time_ms, size_t cards_scanned, size_t heap_used_bytes_before_gc);
// Record the start and end of a full collection.
void record_full_collection_start();
@@ -654,15 +645,7 @@
void record_concurrent_mark_cleanup_end();
void record_concurrent_mark_cleanup_completed();
- // Records the information about the heap size for reporting in
- // print_detailed_heap_transition
- void record_heap_size_info_at_start(bool full);
-
- // Print heap sizing transition (with less and more detail).
-
- void print_detailed_heap_transition() const;
-
- virtual void print_phases(double pause_time_ms);
+ virtual void print_phases();
void record_stop_world_start();
void record_concurrent_pause();
@@ -825,16 +808,6 @@
// The value of _heap_bytes_before_gc is also used to calculate
// the cost of copying.
- size_t _eden_used_bytes_before_gc; // Eden occupancy before GC
- size_t _survivor_used_bytes_before_gc; // Survivor occupancy before GC
- size_t _old_used_bytes_before_gc; // Old occupancy before GC
- size_t _humongous_used_bytes_before_gc; // Humongous occupancy before GC
- size_t _heap_used_bytes_before_gc; // Heap occupancy before GC
- size_t _metaspace_used_bytes_before_gc; // Metaspace occupancy before GC
-
- size_t _eden_capacity_bytes_before_gc; // Eden capacity before GC
- size_t _heap_capacity_bytes_before_gc; // Heap capacity before GC
-
// The amount of survivor regions after a collection.
uint _recorded_survivor_regions;
// List of survivor regions.
@@ -846,6 +819,10 @@
public:
uint tenuring_threshold() const { return _tenuring_threshold; }
+ uint max_survivor_regions() {
+ return _max_survivor_regions;
+ }
+
static const uint REGIONS_UNLIMITED = (uint) -1;
uint max_regions(InCSetState dest) const {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,3682 @@
+/*
+ * Copyright (c) 2001, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/metadataOnStackMark.hpp"
+#include "classfile/symbolTable.hpp"
+#include "code/codeCache.hpp"
+#include "gc/g1/concurrentMarkThread.inline.hpp"
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1CollectorPolicy.hpp"
+#include "gc/g1/g1CollectorState.hpp"
+#include "gc/g1/g1ConcurrentMark.inline.hpp"
+#include "gc/g1/g1HeapVerifier.hpp"
+#include "gc/g1/g1OopClosures.inline.hpp"
+#include "gc/g1/g1StringDedup.hpp"
+#include "gc/g1/heapRegion.inline.hpp"
+#include "gc/g1/heapRegionRemSet.hpp"
+#include "gc/g1/heapRegionSet.inline.hpp"
+#include "gc/g1/suspendibleThreadSet.hpp"
+#include "gc/shared/gcId.hpp"
+#include "gc/shared/gcTimer.hpp"
+#include "gc/shared/gcTrace.hpp"
+#include "gc/shared/gcTraceTime.inline.hpp"
+#include "gc/shared/genOopClosures.inline.hpp"
+#include "gc/shared/referencePolicy.hpp"
+#include "gc/shared/strongRootsScope.hpp"
+#include "gc/shared/taskqueue.inline.hpp"
+#include "gc/shared/vmGCOperations.hpp"
+#include "logging/log.hpp"
+#include "memory/allocation.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/atomic.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/java.hpp"
+#include "runtime/prefetch.inline.hpp"
+#include "services/memTracker.hpp"
+
+// Concurrent marking bit map wrapper
+
+G1CMBitMapRO::G1CMBitMapRO(int shifter) :
+ _bm(),
+ _shifter(shifter) {
+ _bmStartWord = 0;
+ _bmWordSize = 0;
+}
+
+HeapWord* G1CMBitMapRO::getNextMarkedWordAddress(const HeapWord* addr,
+ const HeapWord* limit) const {
+ // First we must round addr *up* to a possible object boundary.
+ addr = (HeapWord*)align_size_up((intptr_t)addr,
+ HeapWordSize << _shifter);
+ size_t addrOffset = heapWordToOffset(addr);
+ assert(limit != NULL, "limit must not be NULL");
+ size_t limitOffset = heapWordToOffset(limit);
+ size_t nextOffset = _bm.get_next_one_offset(addrOffset, limitOffset);
+ HeapWord* nextAddr = offsetToHeapWord(nextOffset);
+ assert(nextAddr >= addr, "get_next_one postcondition");
+ assert(nextAddr == limit || isMarked(nextAddr),
+ "get_next_one postcondition");
+ return nextAddr;
+}
+
+#ifndef PRODUCT
+bool G1CMBitMapRO::covers(MemRegion heap_rs) const {
+ // assert(_bm.map() == _virtual_space.low(), "map inconsistency");
+ assert(((size_t)_bm.size() * ((size_t)1 << _shifter)) == _bmWordSize,
+ "size inconsistency");
+ return _bmStartWord == (HeapWord*)(heap_rs.start()) &&
+ _bmWordSize == heap_rs.word_size();
+}
+#endif
+
+void G1CMBitMapRO::print_on_error(outputStream* st, const char* prefix) const {
+ _bm.print_on_error(st, prefix);
+}
+
+size_t G1CMBitMap::compute_size(size_t heap_size) {
+ return ReservedSpace::allocation_align_size_up(heap_size / mark_distance());
+}
+
+size_t G1CMBitMap::mark_distance() {
+ return MinObjAlignmentInBytes * BitsPerByte;
+}
+
+void G1CMBitMap::initialize(MemRegion heap, G1RegionToSpaceMapper* storage) {
+ _bmStartWord = heap.start();
+ _bmWordSize = heap.word_size();
+
+ _bm.set_map((BitMap::bm_word_t*) storage->reserved().start());
+ _bm.set_size(_bmWordSize >> _shifter);
+
+ storage->set_mapping_changed_listener(&_listener);
+}
+
+void G1CMBitMapMappingChangedListener::on_commit(uint start_region, size_t num_regions, bool zero_filled) {
+ if (zero_filled) {
+ return;
+ }
+ // We need to clear the bitmap on commit, removing any existing information.
+ MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_region), num_regions * HeapRegion::GrainWords);
+ _bm->clearRange(mr);
+}
+
+// Closure used for clearing the given mark bitmap.
+class ClearBitmapHRClosure : public HeapRegionClosure {
+ private:
+ G1ConcurrentMark* _cm;
+ G1CMBitMap* _bitmap;
+ bool _may_yield; // The closure may yield during iteration. If yielded, abort the iteration.
+ public:
+ ClearBitmapHRClosure(G1ConcurrentMark* cm, G1CMBitMap* bitmap, bool may_yield) : HeapRegionClosure(), _cm(cm), _bitmap(bitmap), _may_yield(may_yield) {
+ assert(!may_yield || cm != NULL, "CM must be non-NULL if this closure is expected to yield.");
+ }
+
+ virtual bool doHeapRegion(HeapRegion* r) {
+ size_t const chunk_size_in_words = M / HeapWordSize;
+
+ HeapWord* cur = r->bottom();
+ HeapWord* const end = r->end();
+
+ while (cur < end) {
+ MemRegion mr(cur, MIN2(cur + chunk_size_in_words, end));
+ _bitmap->clearRange(mr);
+
+ cur += chunk_size_in_words;
+
+ // Abort iteration if after yielding the marking has been aborted.
+ if (_may_yield && _cm->do_yield_check() && _cm->has_aborted()) {
+ return true;
+ }
+ // Repeat the asserts from before the start of the closure. We will do them
+ // as asserts here to minimize their overhead on the product. However, we
+ // will have them as guarantees at the beginning / end of the bitmap
+ // clearing to get some checking in the product.
+ assert(!_may_yield || _cm->cmThread()->during_cycle(), "invariant");
+ assert(!_may_yield || !G1CollectedHeap::heap()->collector_state()->mark_in_progress(), "invariant");
+ }
+
+ return false;
+ }
+};
+
+class ParClearNextMarkBitmapTask : public AbstractGangTask {
+ ClearBitmapHRClosure* _cl;
+ HeapRegionClaimer _hrclaimer;
+ bool _suspendible; // If the task is suspendible, workers must join the STS.
+
+public:
+ ParClearNextMarkBitmapTask(ClearBitmapHRClosure *cl, uint n_workers, bool suspendible) :
+ _cl(cl), _suspendible(suspendible), AbstractGangTask("Parallel Clear Bitmap Task"), _hrclaimer(n_workers) {}
+
+ void work(uint worker_id) {
+ SuspendibleThreadSetJoiner sts_join(_suspendible);
+ G1CollectedHeap::heap()->heap_region_par_iterate(_cl, worker_id, &_hrclaimer, true);
+ }
+};
+
+void G1CMBitMap::clearAll() {
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+ ClearBitmapHRClosure cl(NULL, this, false /* may_yield */);
+ uint n_workers = g1h->workers()->active_workers();
+ ParClearNextMarkBitmapTask task(&cl, n_workers, false);
+ g1h->workers()->run_task(&task);
+ guarantee(cl.complete(), "Must have completed iteration.");
+ return;
+}
+
+void G1CMBitMap::clearRange(MemRegion mr) {
+ mr.intersection(MemRegion(_bmStartWord, _bmWordSize));
+ assert(!mr.is_empty(), "unexpected empty region");
+ // convert address range into offset range
+ _bm.at_put_range(heapWordToOffset(mr.start()),
+ heapWordToOffset(mr.end()), false);
+}
+
+G1CMMarkStack::G1CMMarkStack(G1ConcurrentMark* cm) :
+ _base(NULL), _cm(cm)
+{}
+
+bool G1CMMarkStack::allocate(size_t capacity) {
+ // allocate a stack of the requisite depth
+ ReservedSpace rs(ReservedSpace::allocation_align_size_up(capacity * sizeof(oop)));
+ if (!rs.is_reserved()) {
+ warning("ConcurrentMark MarkStack allocation failure");
+ return false;
+ }
+ MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
+ if (!_virtual_space.initialize(rs, rs.size())) {
+ warning("ConcurrentMark MarkStack backing store failure");
+ // Release the virtual memory reserved for the marking stack
+ rs.release();
+ return false;
+ }
+ assert(_virtual_space.committed_size() == rs.size(),
+ "Didn't reserve backing store for all of G1ConcurrentMark stack?");
+ _base = (oop*) _virtual_space.low();
+ setEmpty();
+ _capacity = (jint) capacity;
+ _saved_index = -1;
+ _should_expand = false;
+ return true;
+}
+
+void G1CMMarkStack::expand() {
+ // Called, during remark, if we've overflown the marking stack during marking.
+ assert(isEmpty(), "stack should been emptied while handling overflow");
+ assert(_capacity <= (jint) MarkStackSizeMax, "stack bigger than permitted");
+ // Clear expansion flag
+ _should_expand = false;
+ if (_capacity == (jint) MarkStackSizeMax) {
+ log_trace(gc)("(benign) Can't expand marking stack capacity, at max size limit");
+ return;
+ }
+ // Double capacity if possible
+ jint new_capacity = MIN2(_capacity*2, (jint) MarkStackSizeMax);
+ // Do not give up existing stack until we have managed to
+ // get the double capacity that we desired.
+ ReservedSpace rs(ReservedSpace::allocation_align_size_up(new_capacity *
+ sizeof(oop)));
+ if (rs.is_reserved()) {
+ // Release the backing store associated with old stack
+ _virtual_space.release();
+ // Reinitialize virtual space for new stack
+ if (!_virtual_space.initialize(rs, rs.size())) {
+ fatal("Not enough swap for expanded marking stack capacity");
+ }
+ _base = (oop*)(_virtual_space.low());
+ _index = 0;
+ _capacity = new_capacity;
+ } else {
+ // Failed to double capacity, continue;
+ log_trace(gc)("(benign) Failed to expand marking stack capacity from " SIZE_FORMAT "K to " SIZE_FORMAT "K",
+ _capacity / K, new_capacity / K);
+ }
+}
+
+void G1CMMarkStack::set_should_expand() {
+ // If we're resetting the marking state because of an
+ // marking stack overflow, record that we should, if
+ // possible, expand the stack.
+ _should_expand = _cm->has_overflown();
+}
+
+G1CMMarkStack::~G1CMMarkStack() {
+ if (_base != NULL) {
+ _base = NULL;
+ _virtual_space.release();
+ }
+}
+
+void G1CMMarkStack::par_push_arr(oop* ptr_arr, int n) {
+ MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
+ jint start = _index;
+ jint next_index = start + n;
+ if (next_index > _capacity) {
+ _overflow = true;
+ return;
+ }
+ // Otherwise.
+ _index = next_index;
+ for (int i = 0; i < n; i++) {
+ int ind = start + i;
+ assert(ind < _capacity, "By overflow test above.");
+ _base[ind] = ptr_arr[i];
+ }
+}
+
+bool G1CMMarkStack::par_pop_arr(oop* ptr_arr, int max, int* n) {
+ MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
+ jint index = _index;
+ if (index == 0) {
+ *n = 0;
+ return false;
+ } else {
+ int k = MIN2(max, index);
+ jint new_ind = index - k;
+ for (int j = 0; j < k; j++) {
+ ptr_arr[j] = _base[new_ind + j];
+ }
+ _index = new_ind;
+ *n = k;
+ return true;
+ }
+}
+
+void G1CMMarkStack::note_start_of_gc() {
+ assert(_saved_index == -1,
+ "note_start_of_gc()/end_of_gc() bracketed incorrectly");
+ _saved_index = _index;
+}
+
+void G1CMMarkStack::note_end_of_gc() {
+ // This is intentionally a guarantee, instead of an assert. If we
+ // accidentally add something to the mark stack during GC, it
+ // will be a correctness issue so it's better if we crash. we'll
+ // only check this once per GC anyway, so it won't be a performance
+ // issue in any way.
+ guarantee(_saved_index == _index,
+ "saved index: %d index: %d", _saved_index, _index);
+ _saved_index = -1;
+}
+
+G1CMRootRegions::G1CMRootRegions() :
+ _young_list(NULL), _cm(NULL), _scan_in_progress(false),
+ _should_abort(false), _next_survivor(NULL) { }
+
+void G1CMRootRegions::init(G1CollectedHeap* g1h, G1ConcurrentMark* cm) {
+ _young_list = g1h->young_list();
+ _cm = cm;
+}
+
+void G1CMRootRegions::prepare_for_scan() {
+ assert(!scan_in_progress(), "pre-condition");
+
+ // Currently, only survivors can be root regions.
+ assert(_next_survivor == NULL, "pre-condition");
+ _next_survivor = _young_list->first_survivor_region();
+ _scan_in_progress = (_next_survivor != NULL);
+ _should_abort = false;
+}
+
+HeapRegion* G1CMRootRegions::claim_next() {
+ if (_should_abort) {
+ // If someone has set the should_abort flag, we return NULL to
+ // force the caller to bail out of their loop.
+ return NULL;
+ }
+
+ // Currently, only survivors can be root regions.
+ HeapRegion* res = _next_survivor;
+ if (res != NULL) {
+ MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
+ // Read it again in case it changed while we were waiting for the lock.
+ res = _next_survivor;
+ if (res != NULL) {
+ if (res == _young_list->last_survivor_region()) {
+ // We just claimed the last survivor so store NULL to indicate
+ // that we're done.
+ _next_survivor = NULL;
+ } else {
+ _next_survivor = res->get_next_young_region();
+ }
+ } else {
+ // Someone else claimed the last survivor while we were trying
+ // to take the lock so nothing else to do.
+ }
+ }
+ assert(res == NULL || res->is_survivor(), "post-condition");
+
+ return res;
+}
+
+void G1CMRootRegions::scan_finished() {
+ assert(scan_in_progress(), "pre-condition");
+
+ // Currently, only survivors can be root regions.
+ if (!_should_abort) {
+ assert(_next_survivor == NULL, "we should have claimed all survivors");
+ }
+ _next_survivor = NULL;
+
+ {
+ MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
+ _scan_in_progress = false;
+ RootRegionScan_lock->notify_all();
+ }
+}
+
+bool G1CMRootRegions::wait_until_scan_finished() {
+ if (!scan_in_progress()) return false;
+
+ {
+ MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
+ while (scan_in_progress()) {
+ RootRegionScan_lock->wait(Mutex::_no_safepoint_check_flag);
+ }
+ }
+ return true;
+}
+
+uint G1ConcurrentMark::scale_parallel_threads(uint n_par_threads) {
+ return MAX2((n_par_threads + 2) / 4, 1U);
+}
+
+G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev_bitmap_storage, G1RegionToSpaceMapper* next_bitmap_storage) :
+ _g1h(g1h),
+ _markBitMap1(),
+ _markBitMap2(),
+ _parallel_marking_threads(0),
+ _max_parallel_marking_threads(0),
+ _sleep_factor(0.0),
+ _marking_task_overhead(1.0),
+ _cleanup_list("Cleanup List"),
+ _region_bm((BitMap::idx_t)(g1h->max_regions()), false /* in_resource_area*/),
+ _card_bm((g1h->reserved_region().byte_size() + CardTableModRefBS::card_size - 1) >>
+ CardTableModRefBS::card_shift,
+ false /* in_resource_area*/),
+
+ _prevMarkBitMap(&_markBitMap1),
+ _nextMarkBitMap(&_markBitMap2),
+
+ _markStack(this),
+ // _finger set in set_non_marking_state
+
+ _max_worker_id(ParallelGCThreads),
+ // _active_tasks set in set_non_marking_state
+ // _tasks set inside the constructor
+ _task_queues(new G1CMTaskQueueSet((int) _max_worker_id)),
+ _terminator(ParallelTaskTerminator((int) _max_worker_id, _task_queues)),
+
+ _has_overflown(false),
+ _concurrent(false),
+ _has_aborted(false),
+ _restart_for_overflow(false),
+ _concurrent_marking_in_progress(false),
+ _concurrent_phase_started(false),
+
+ // _verbose_level set below
+
+ _init_times(),
+ _remark_times(), _remark_mark_times(), _remark_weak_ref_times(),
+ _cleanup_times(),
+ _total_counting_time(0.0),
+ _total_rs_scrub_time(0.0),
+
+ _parallel_workers(NULL),
+
+ _count_card_bitmaps(NULL),
+ _count_marked_bytes(NULL),
+ _completed_initialization(false) {
+
+ _markBitMap1.initialize(g1h->reserved_region(), prev_bitmap_storage);
+ _markBitMap2.initialize(g1h->reserved_region(), next_bitmap_storage);
+
+ // Create & start a ConcurrentMark thread.
+ _cmThread = new ConcurrentMarkThread(this);
+ assert(cmThread() != NULL, "CM Thread should have been created");
+ assert(cmThread()->cm() != NULL, "CM Thread should refer to this cm");
+ if (_cmThread->osthread() == NULL) {
+ vm_shutdown_during_initialization("Could not create ConcurrentMarkThread");
+ }
+
+ assert(CGC_lock != NULL, "Where's the CGC_lock?");
+ assert(_markBitMap1.covers(g1h->reserved_region()), "_markBitMap1 inconsistency");
+ assert(_markBitMap2.covers(g1h->reserved_region()), "_markBitMap2 inconsistency");
+
+ SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set();
+ satb_qs.set_buffer_size(G1SATBBufferSize);
+
+ _root_regions.init(_g1h, this);
+
+ if (ConcGCThreads > ParallelGCThreads) {
+ warning("Can't have more ConcGCThreads (%u) "
+ "than ParallelGCThreads (%u).",
+ ConcGCThreads, ParallelGCThreads);
+ return;
+ }
+ if (!FLAG_IS_DEFAULT(ConcGCThreads) && ConcGCThreads > 0) {
+ // Note: ConcGCThreads has precedence over G1MarkingOverheadPercent
+ // if both are set
+ _sleep_factor = 0.0;
+ _marking_task_overhead = 1.0;
+ } else if (G1MarkingOverheadPercent > 0) {
+ // We will calculate the number of parallel marking threads based
+ // on a target overhead with respect to the soft real-time goal
+ double marking_overhead = (double) G1MarkingOverheadPercent / 100.0;
+ double overall_cm_overhead =
+ (double) MaxGCPauseMillis * marking_overhead /
+ (double) GCPauseIntervalMillis;
+ double cpu_ratio = 1.0 / (double) os::processor_count();
+ double marking_thread_num = ceil(overall_cm_overhead / cpu_ratio);
+ double marking_task_overhead =
+ overall_cm_overhead / marking_thread_num *
+ (double) os::processor_count();
+ double sleep_factor =
+ (1.0 - marking_task_overhead) / marking_task_overhead;
+
+ FLAG_SET_ERGO(uint, ConcGCThreads, (uint) marking_thread_num);
+ _sleep_factor = sleep_factor;
+ _marking_task_overhead = marking_task_overhead;
+ } else {
+ // Calculate the number of parallel marking threads by scaling
+ // the number of parallel GC threads.
+ uint marking_thread_num = scale_parallel_threads(ParallelGCThreads);
+ FLAG_SET_ERGO(uint, ConcGCThreads, marking_thread_num);
+ _sleep_factor = 0.0;
+ _marking_task_overhead = 1.0;
+ }
+
+ assert(ConcGCThreads > 0, "Should have been set");
+ _parallel_marking_threads = ConcGCThreads;
+ _max_parallel_marking_threads = _parallel_marking_threads;
+
+ _parallel_workers = new WorkGang("G1 Marker",
+ _max_parallel_marking_threads, false, true);
+ if (_parallel_workers == NULL) {
+ vm_exit_during_initialization("Failed necessary allocation.");
+ } else {
+ _parallel_workers->initialize_workers();
+ }
+
+ if (FLAG_IS_DEFAULT(MarkStackSize)) {
+ size_t mark_stack_size =
+ MIN2(MarkStackSizeMax,
+ MAX2(MarkStackSize, (size_t) (parallel_marking_threads() * TASKQUEUE_SIZE)));
+ // Verify that the calculated value for MarkStackSize is in range.
+ // It would be nice to use the private utility routine from Arguments.
+ if (!(mark_stack_size >= 1 && mark_stack_size <= MarkStackSizeMax)) {
+ warning("Invalid value calculated for MarkStackSize (" SIZE_FORMAT "): "
+ "must be between 1 and " SIZE_FORMAT,
+ mark_stack_size, MarkStackSizeMax);
+ return;
+ }
+ FLAG_SET_ERGO(size_t, MarkStackSize, mark_stack_size);
+ } else {
+ // Verify MarkStackSize is in range.
+ if (FLAG_IS_CMDLINE(MarkStackSize)) {
+ if (FLAG_IS_DEFAULT(MarkStackSizeMax)) {
+ if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
+ warning("Invalid value specified for MarkStackSize (" SIZE_FORMAT "): "
+ "must be between 1 and " SIZE_FORMAT,
+ MarkStackSize, MarkStackSizeMax);
+ return;
+ }
+ } else if (FLAG_IS_CMDLINE(MarkStackSizeMax)) {
+ if (!(MarkStackSize >= 1 && MarkStackSize <= MarkStackSizeMax)) {
+ warning("Invalid value specified for MarkStackSize (" SIZE_FORMAT ")"
+ " or for MarkStackSizeMax (" SIZE_FORMAT ")",
+ MarkStackSize, MarkStackSizeMax);
+ return;
+ }
+ }
+ }
+ }
+
+ if (!_markStack.allocate(MarkStackSize)) {
+ warning("Failed to allocate CM marking stack");
+ return;
+ }
+
+ _tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC);
+ _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC);
+
+ _count_card_bitmaps = NEW_C_HEAP_ARRAY(BitMap, _max_worker_id, mtGC);
+ _count_marked_bytes = NEW_C_HEAP_ARRAY(size_t*, _max_worker_id, mtGC);
+
+ BitMap::idx_t card_bm_size = _card_bm.size();
+
+ // so that the assertion in MarkingTaskQueue::task_queue doesn't fail
+ _active_tasks = _max_worker_id;
+
+ uint max_regions = _g1h->max_regions();
+ for (uint i = 0; i < _max_worker_id; ++i) {
+ G1CMTaskQueue* task_queue = new G1CMTaskQueue();
+ task_queue->initialize();
+ _task_queues->register_queue(i, task_queue);
+
+ _count_card_bitmaps[i] = BitMap(card_bm_size, false);
+ _count_marked_bytes[i] = NEW_C_HEAP_ARRAY(size_t, max_regions, mtGC);
+
+ _tasks[i] = new G1CMTask(i, this,
+ _count_marked_bytes[i],
+ &_count_card_bitmaps[i],
+ task_queue, _task_queues);
+
+ _accum_task_vtime[i] = 0.0;
+ }
+
+ // Calculate the card number for the bottom of the heap. Used
+ // in biasing indexes into the accounting card bitmaps.
+ _heap_bottom_card_num =
+ intptr_t(uintptr_t(_g1h->reserved_region().start()) >>
+ CardTableModRefBS::card_shift);
+
+ // Clear all the liveness counting data
+ clear_all_count_data();
+
+ // so that the call below can read a sensible value
+ _heap_start = g1h->reserved_region().start();
+ set_non_marking_state();
+ _completed_initialization = true;
+}
+
+void G1ConcurrentMark::reset() {
+ // Starting values for these two. This should be called in a STW
+ // phase.
+ MemRegion reserved = _g1h->g1_reserved();
+ _heap_start = reserved.start();
+ _heap_end = reserved.end();
+
+ // Separated the asserts so that we know which one fires.
+ assert(_heap_start != NULL, "heap bounds should look ok");
+ assert(_heap_end != NULL, "heap bounds should look ok");
+ assert(_heap_start < _heap_end, "heap bounds should look ok");
+
+ // Reset all the marking data structures and any necessary flags
+ reset_marking_state();
+
+ // We do reset all of them, since different phases will use
+ // different number of active threads. So, it's easiest to have all
+ // of them ready.
+ for (uint i = 0; i < _max_worker_id; ++i) {
+ _tasks[i]->reset(_nextMarkBitMap);
+ }
+
+ // we need this to make sure that the flag is on during the evac
+ // pause with initial mark piggy-backed
+ set_concurrent_marking_in_progress();
+}
+
+
+void G1ConcurrentMark::reset_marking_state(bool clear_overflow) {
+ _markStack.set_should_expand();
+ _markStack.setEmpty(); // Also clears the _markStack overflow flag
+ if (clear_overflow) {
+ clear_has_overflown();
+ } else {
+ assert(has_overflown(), "pre-condition");
+ }
+ _finger = _heap_start;
+
+ for (uint i = 0; i < _max_worker_id; ++i) {
+ G1CMTaskQueue* queue = _task_queues->queue(i);
+ queue->set_empty();
+ }
+}
+
+void G1ConcurrentMark::set_concurrency(uint active_tasks) {
+ assert(active_tasks <= _max_worker_id, "we should not have more");
+
+ _active_tasks = active_tasks;
+ // Need to update the three data structures below according to the
+ // number of active threads for this phase.
+ _terminator = ParallelTaskTerminator((int) active_tasks, _task_queues);
+ _first_overflow_barrier_sync.set_n_workers((int) active_tasks);
+ _second_overflow_barrier_sync.set_n_workers((int) active_tasks);
+}
+
+void G1ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurrent) {
+ set_concurrency(active_tasks);
+
+ _concurrent = concurrent;
+ // We propagate this to all tasks, not just the active ones.
+ for (uint i = 0; i < _max_worker_id; ++i)
+ _tasks[i]->set_concurrent(concurrent);
+
+ if (concurrent) {
+ set_concurrent_marking_in_progress();
+ } else {
+ // We currently assume that the concurrent flag has been set to
+ // false before we start remark. At this point we should also be
+ // in a STW phase.
+ assert(!concurrent_marking_in_progress(), "invariant");
+ assert(out_of_regions(),
+ "only way to get here: _finger: " PTR_FORMAT ", _heap_end: " PTR_FORMAT,
+ p2i(_finger), p2i(_heap_end));
+ }
+}
+
+void G1ConcurrentMark::set_non_marking_state() {
+ // We set the global marking state to some default values when we're
+ // not doing marking.
+ reset_marking_state();
+ _active_tasks = 0;
+ clear_concurrent_marking_in_progress();
+}
+
+G1ConcurrentMark::~G1ConcurrentMark() {
+ // The G1ConcurrentMark instance is never freed.
+ ShouldNotReachHere();
+}
+
+void G1ConcurrentMark::clearNextBitmap() {
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+ // Make sure that the concurrent mark thread looks to still be in
+ // the current cycle.
+ guarantee(cmThread()->during_cycle(), "invariant");
+
+ // We are finishing up the current cycle by clearing the next
+ // marking bitmap and getting it ready for the next cycle. During
+ // this time no other cycle can start. So, let's make sure that this
+ // is the case.
+ guarantee(!g1h->collector_state()->mark_in_progress(), "invariant");
+
+ ClearBitmapHRClosure cl(this, _nextMarkBitMap, true /* may_yield */);
+ ParClearNextMarkBitmapTask task(&cl, parallel_marking_threads(), true);
+ _parallel_workers->run_task(&task);
+
+ // Clear the liveness counting data. If the marking has been aborted, the abort()
+ // call already did that.
+ if (cl.complete()) {
+ clear_all_count_data();
+ }
+
+ // Repeat the asserts from above.
+ guarantee(cmThread()->during_cycle(), "invariant");
+ guarantee(!g1h->collector_state()->mark_in_progress(), "invariant");
+}
+
+class CheckBitmapClearHRClosure : public HeapRegionClosure {
+ G1CMBitMap* _bitmap;
+ bool _error;
+ public:
+ CheckBitmapClearHRClosure(G1CMBitMap* bitmap) : _bitmap(bitmap) {
+ }
+
+ virtual bool doHeapRegion(HeapRegion* r) {
+ // This closure can be called concurrently to the mutator, so we must make sure
+ // that the result of the getNextMarkedWordAddress() call is compared to the
+ // value passed to it as limit to detect any found bits.
+ // end never changes in G1.
+ HeapWord* end = r->end();
+ return _bitmap->getNextMarkedWordAddress(r->bottom(), end) != end;
+ }
+};
+
+bool G1ConcurrentMark::nextMarkBitmapIsClear() {
+ CheckBitmapClearHRClosure cl(_nextMarkBitMap);
+ _g1h->heap_region_iterate(&cl);
+ return cl.complete();
+}
+
+class NoteStartOfMarkHRClosure: public HeapRegionClosure {
+public:
+ bool doHeapRegion(HeapRegion* r) {
+ r->note_start_of_marking();
+ return false;
+ }
+};
+
+void G1ConcurrentMark::checkpointRootsInitialPre() {
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+ G1CollectorPolicy* g1p = g1h->g1_policy();
+
+ _has_aborted = false;
+
+ // Initialize marking structures. This has to be done in a STW phase.
+ reset();
+
+ // For each region note start of marking.
+ NoteStartOfMarkHRClosure startcl;
+ g1h->heap_region_iterate(&startcl);
+}
+
+
+void G1ConcurrentMark::checkpointRootsInitialPost() {
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+ // Start Concurrent Marking weak-reference discovery.
+ ReferenceProcessor* rp = g1h->ref_processor_cm();
+ // enable ("weak") refs discovery
+ rp->enable_discovery();
+ rp->setup_policy(false); // snapshot the soft ref policy to be used in this cycle
+
+ SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
+ // This is the start of the marking cycle, we're expected all
+ // threads to have SATB queues with active set to false.
+ satb_mq_set.set_active_all_threads(true, /* new active value */
+ false /* expected_active */);
+
+ _root_regions.prepare_for_scan();
+
+ // update_g1_committed() will be called at the end of an evac pause
+ // when marking is on. So, it's also called at the end of the
+ // initial-mark pause to update the heap end, if the heap expands
+ // during it. No need to call it here.
+}
+
+/*
+ * Notice that in the next two methods, we actually leave the STS
+ * during the barrier sync and join it immediately afterwards. If we
+ * do not do this, the following deadlock can occur: one thread could
+ * be in the barrier sync code, waiting for the other thread to also
+ * sync up, whereas another one could be trying to yield, while also
+ * waiting for the other threads to sync up too.
+ *
+ * Note, however, that this code is also used during remark and in
+ * this case we should not attempt to leave / enter the STS, otherwise
+ * we'll either hit an assert (debug / fastdebug) or deadlock
+ * (product). So we should only leave / enter the STS if we are
+ * operating concurrently.
+ *
+ * Because the thread that does the sync barrier has left the STS, it
+ * is possible to be suspended for a Full GC or an evacuation pause
+ * could occur. This is actually safe, since the entering the sync
+ * barrier is one of the last things do_marking_step() does, and it
+ * doesn't manipulate any data structures afterwards.
+ */
+
+void G1ConcurrentMark::enter_first_sync_barrier(uint worker_id) {
+ bool barrier_aborted;
+ {
+ SuspendibleThreadSetLeaver sts_leave(concurrent());
+ barrier_aborted = !_first_overflow_barrier_sync.enter();
+ }
+
+ // at this point everyone should have synced up and not be doing any
+ // more work
+
+ if (barrier_aborted) {
+ // If the barrier aborted we ignore the overflow condition and
+ // just abort the whole marking phase as quickly as possible.
+ return;
+ }
+
+ // If we're executing the concurrent phase of marking, reset the marking
+ // state; otherwise the marking state is reset after reference processing,
+ // during the remark pause.
+ // If we reset here as a result of an overflow during the remark we will
+ // see assertion failures from any subsequent set_concurrency_and_phase()
+ // calls.
+ if (concurrent()) {
+ // let the task associated with with worker 0 do this
+ if (worker_id == 0) {
+ // task 0 is responsible for clearing the global data structures
+ // We should be here because of an overflow. During STW we should
+ // not clear the overflow flag since we rely on it being true when
+ // we exit this method to abort the pause and restart concurrent
+ // marking.
+ reset_marking_state(true /* clear_overflow */);
+
+ log_info(gc)("Concurrent Mark reset for overflow");
+ }
+ }
+
+ // after this, each task should reset its own data structures then
+ // then go into the second barrier
+}
+
+void G1ConcurrentMark::enter_second_sync_barrier(uint worker_id) {
+ SuspendibleThreadSetLeaver sts_leave(concurrent());
+ _second_overflow_barrier_sync.enter();
+
+ // at this point everything should be re-initialized and ready to go
+}
+
+class G1CMConcurrentMarkingTask: public AbstractGangTask {
+private:
+ G1ConcurrentMark* _cm;
+ ConcurrentMarkThread* _cmt;
+
+public:
+ void work(uint worker_id) {
+ assert(Thread::current()->is_ConcurrentGC_thread(),
+ "this should only be done by a conc GC thread");
+ ResourceMark rm;
+
+ double start_vtime = os::elapsedVTime();
+
+ {
+ SuspendibleThreadSetJoiner sts_join;
+
+ assert(worker_id < _cm->active_tasks(), "invariant");
+ G1CMTask* the_task = _cm->task(worker_id);
+ the_task->record_start_time();
+ if (!_cm->has_aborted()) {
+ do {
+ double start_vtime_sec = os::elapsedVTime();
+ double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
+
+ the_task->do_marking_step(mark_step_duration_ms,
+ true /* do_termination */,
+ false /* is_serial*/);
+
+ double end_vtime_sec = os::elapsedVTime();
+ double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec;
+ _cm->clear_has_overflown();
+
+ _cm->do_yield_check(worker_id);
+
+ jlong sleep_time_ms;
+ if (!_cm->has_aborted() && the_task->has_aborted()) {
+ sleep_time_ms =
+ (jlong) (elapsed_vtime_sec * _cm->sleep_factor() * 1000.0);
+ {
+ SuspendibleThreadSetLeaver sts_leave;
+ os::sleep(Thread::current(), sleep_time_ms, false);
+ }
+ }
+ } while (!_cm->has_aborted() && the_task->has_aborted());
+ }
+ the_task->record_end_time();
+ guarantee(!the_task->has_aborted() || _cm->has_aborted(), "invariant");
+ }
+
+ double end_vtime = os::elapsedVTime();
+ _cm->update_accum_task_vtime(worker_id, end_vtime - start_vtime);
+ }
+
+ G1CMConcurrentMarkingTask(G1ConcurrentMark* cm,
+ ConcurrentMarkThread* cmt) :
+ AbstractGangTask("Concurrent Mark"), _cm(cm), _cmt(cmt) { }
+
+ ~G1CMConcurrentMarkingTask() { }
+};
+
+// Calculates the number of active workers for a concurrent
+// phase.
+uint G1ConcurrentMark::calc_parallel_marking_threads() {
+ uint n_conc_workers = 0;
+ if (!UseDynamicNumberOfGCThreads ||
+ (!FLAG_IS_DEFAULT(ConcGCThreads) &&
+ !ForceDynamicNumberOfGCThreads)) {
+ n_conc_workers = max_parallel_marking_threads();
+ } else {
+ n_conc_workers =
+ AdaptiveSizePolicy::calc_default_active_workers(
+ max_parallel_marking_threads(),
+ 1, /* Minimum workers */
+ parallel_marking_threads(),
+ Threads::number_of_non_daemon_threads());
+ // Don't scale down "n_conc_workers" by scale_parallel_threads() because
+ // that scaling has already gone into "_max_parallel_marking_threads".
+ }
+ assert(n_conc_workers > 0, "Always need at least 1");
+ return n_conc_workers;
+}
+
+void G1ConcurrentMark::scanRootRegion(HeapRegion* hr, uint worker_id) {
+ // Currently, only survivors can be root regions.
+ assert(hr->next_top_at_mark_start() == hr->bottom(), "invariant");
+ G1RootRegionScanClosure cl(_g1h, this, worker_id);
+
+ const uintx interval = PrefetchScanIntervalInBytes;
+ HeapWord* curr = hr->bottom();
+ const HeapWord* end = hr->top();
+ while (curr < end) {
+ Prefetch::read(curr, interval);
+ oop obj = oop(curr);
+ int size = obj->oop_iterate_size(&cl);
+ assert(size == obj->size(), "sanity");
+ curr += size;
+ }
+}
+
+class G1CMRootRegionScanTask : public AbstractGangTask {
+private:
+ G1ConcurrentMark* _cm;
+
+public:
+ G1CMRootRegionScanTask(G1ConcurrentMark* cm) :
+ AbstractGangTask("Root Region Scan"), _cm(cm) { }
+
+ void work(uint worker_id) {
+ assert(Thread::current()->is_ConcurrentGC_thread(),
+ "this should only be done by a conc GC thread");
+
+ G1CMRootRegions* root_regions = _cm->root_regions();
+ HeapRegion* hr = root_regions->claim_next();
+ while (hr != NULL) {
+ _cm->scanRootRegion(hr, worker_id);
+ hr = root_regions->claim_next();
+ }
+ }
+};
+
+void G1ConcurrentMark::scanRootRegions() {
+ // Start of concurrent marking.
+ ClassLoaderDataGraph::clear_claimed_marks();
+
+ // scan_in_progress() will have been set to true only if there was
+ // at least one root region to scan. So, if it's false, we
+ // should not attempt to do any further work.
+ if (root_regions()->scan_in_progress()) {
+ GCTraceConcTime(Info, gc) tt("Concurrent Root Region Scan");
+
+ _parallel_marking_threads = calc_parallel_marking_threads();
+ assert(parallel_marking_threads() <= max_parallel_marking_threads(),
+ "Maximum number of marking threads exceeded");
+ uint active_workers = MAX2(1U, parallel_marking_threads());
+
+ G1CMRootRegionScanTask task(this);
+ _parallel_workers->set_active_workers(active_workers);
+ _parallel_workers->run_task(&task);
+
+ // It's possible that has_aborted() is true here without actually
+ // aborting the survivor scan earlier. This is OK as it's
+ // mainly used for sanity checking.
+ root_regions()->scan_finished();
+ }
+}
+
+void G1ConcurrentMark::register_concurrent_phase_start(const char* title) {
+ assert(!_concurrent_phase_started, "Sanity");
+ _concurrent_phase_started = true;
+ _g1h->gc_timer_cm()->register_gc_concurrent_start(title);
+}
+
+void G1ConcurrentMark::register_concurrent_phase_end() {
+ if (_concurrent_phase_started) {
+ _concurrent_phase_started = false;
+ _g1h->gc_timer_cm()->register_gc_concurrent_end();
+ }
+}
+
+void G1ConcurrentMark::markFromRoots() {
+ // we might be tempted to assert that:
+ // assert(asynch == !SafepointSynchronize::is_at_safepoint(),
+ // "inconsistent argument?");
+ // However that wouldn't be right, because it's possible that
+ // a safepoint is indeed in progress as a younger generation
+ // stop-the-world GC happens even as we mark in this generation.
+
+ _restart_for_overflow = false;
+
+ // _g1h has _n_par_threads
+ _parallel_marking_threads = calc_parallel_marking_threads();
+ assert(parallel_marking_threads() <= max_parallel_marking_threads(),
+ "Maximum number of marking threads exceeded");
+
+ uint active_workers = MAX2(1U, parallel_marking_threads());
+ assert(active_workers > 0, "Should have been set");
+
+ // Parallel task terminator is set in "set_concurrency_and_phase()"
+ set_concurrency_and_phase(active_workers, true /* concurrent */);
+
+ G1CMConcurrentMarkingTask markingTask(this, cmThread());
+ _parallel_workers->set_active_workers(active_workers);
+ _parallel_workers->run_task(&markingTask);
+ print_stats();
+}
+
+void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
+ // world is stopped at this checkpoint
+ assert(SafepointSynchronize::is_at_safepoint(),
+ "world should be stopped");
+
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+ // If a full collection has happened, we shouldn't do this.
+ if (has_aborted()) {
+ g1h->collector_state()->set_mark_in_progress(false); // So bitmap clearing isn't confused
+ return;
+ }
+
+ SvcGCMarker sgcm(SvcGCMarker::OTHER);
+
+ if (VerifyDuringGC) {
+ HandleMark hm; // handle scope
+ g1h->prepare_for_verify();
+ Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (before)");
+ }
+ g1h->verifier()->check_bitmaps("Remark Start");
+
+ G1CollectorPolicy* g1p = g1h->g1_policy();
+ g1p->record_concurrent_mark_remark_start();
+
+ double start = os::elapsedTime();
+
+ checkpointRootsFinalWork();
+
+ double mark_work_end = os::elapsedTime();
+
+ weakRefsWork(clear_all_soft_refs);
+
+ if (has_overflown()) {
+ // Oops. We overflowed. Restart concurrent marking.
+ _restart_for_overflow = true;
+ log_develop_trace(gc)("Remark led to restart for overflow.");
+
+ // Verify the heap w.r.t. the previous marking bitmap.
+ if (VerifyDuringGC) {
+ HandleMark hm; // handle scope
+ g1h->prepare_for_verify();
+ Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (overflow)");
+ }
+
+ // Clear the marking state because we will be restarting
+ // marking due to overflowing the global mark stack.
+ reset_marking_state();
+ } else {
+ {
+ GCTraceTime(Debug, gc) trace("GC Aggregate Data", g1h->gc_timer_cm());
+
+ // Aggregate the per-task counting data that we have accumulated
+ // while marking.
+ aggregate_count_data();
+ }
+
+ SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
+ // We're done with marking.
+ // This is the end of the marking cycle, we're expected all
+ // threads to have SATB queues with active set to true.
+ satb_mq_set.set_active_all_threads(false, /* new active value */
+ true /* expected_active */);
+
+ if (VerifyDuringGC) {
+ HandleMark hm; // handle scope
+ g1h->prepare_for_verify();
+ Universe::verify(VerifyOption_G1UseNextMarking, "During GC (after)");
+ }
+ g1h->verifier()->check_bitmaps("Remark End");
+ assert(!restart_for_overflow(), "sanity");
+ // Completely reset the marking state since marking completed
+ set_non_marking_state();
+ }
+
+ // Expand the marking stack, if we have to and if we can.
+ if (_markStack.should_expand()) {
+ _markStack.expand();
+ }
+
+ // Statistics
+ double now = os::elapsedTime();
+ _remark_mark_times.add((mark_work_end - start) * 1000.0);
+ _remark_weak_ref_times.add((now - mark_work_end) * 1000.0);
+ _remark_times.add((now - start) * 1000.0);
+
+ g1p->record_concurrent_mark_remark_end();
+
+ G1CMIsAliveClosure is_alive(g1h);
+ g1h->gc_tracer_cm()->report_object_count_after_gc(&is_alive);
+}
+
+// Base class of the closures that finalize and verify the
+// liveness counting data.
+class G1CMCountDataClosureBase: public HeapRegionClosure {
+protected:
+ G1CollectedHeap* _g1h;
+ G1ConcurrentMark* _cm;
+ CardTableModRefBS* _ct_bs;
+
+ BitMap* _region_bm;
+ BitMap* _card_bm;
+
+ // Takes a region that's not empty (i.e., it has at least one
+ // live object in it and sets its corresponding bit on the region
+ // bitmap to 1.
+ void set_bit_for_region(HeapRegion* hr) {
+ BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
+ _region_bm->par_at_put(index, true);
+ }
+
+public:
+ G1CMCountDataClosureBase(G1CollectedHeap* g1h,
+ BitMap* region_bm, BitMap* card_bm):
+ _g1h(g1h), _cm(g1h->concurrent_mark()),
+ _ct_bs(barrier_set_cast<CardTableModRefBS>(g1h->barrier_set())),
+ _region_bm(region_bm), _card_bm(card_bm) { }
+};
+
+// Closure that calculates the # live objects per region. Used
+// for verification purposes during the cleanup pause.
+class CalcLiveObjectsClosure: public G1CMCountDataClosureBase {
+ G1CMBitMapRO* _bm;
+ size_t _region_marked_bytes;
+
+public:
+ CalcLiveObjectsClosure(G1CMBitMapRO *bm, G1CollectedHeap* g1h,
+ BitMap* region_bm, BitMap* card_bm) :
+ G1CMCountDataClosureBase(g1h, region_bm, card_bm),
+ _bm(bm), _region_marked_bytes(0) { }
+
+ bool doHeapRegion(HeapRegion* hr) {
+ HeapWord* ntams = hr->next_top_at_mark_start();
+ HeapWord* start = hr->bottom();
+
+ assert(start <= hr->end() && start <= ntams && ntams <= hr->end(),
+ "Preconditions not met - "
+ "start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT,
+ p2i(start), p2i(ntams), p2i(hr->end()));
+
+ // Find the first marked object at or after "start".
+ start = _bm->getNextMarkedWordAddress(start, ntams);
+
+ size_t marked_bytes = 0;
+
+ while (start < ntams) {
+ oop obj = oop(start);
+ int obj_sz = obj->size();
+ HeapWord* obj_end = start + obj_sz;
+
+ BitMap::idx_t start_idx = _cm->card_bitmap_index_for(start);
+ BitMap::idx_t end_idx = _cm->card_bitmap_index_for(obj_end);
+
+ // Note: if we're looking at the last region in heap - obj_end
+ // could be actually just beyond the end of the heap; end_idx
+ // will then correspond to a (non-existent) card that is also
+ // just beyond the heap.
+ if (_g1h->is_in_g1_reserved(obj_end) && !_ct_bs->is_card_aligned(obj_end)) {
+ // end of object is not card aligned - increment to cover
+ // all the cards spanned by the object
+ end_idx += 1;
+ }
+
+ // Set the bits in the card BM for the cards spanned by this object.
+ _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */);
+
+ // Add the size of this object to the number of marked bytes.
+ marked_bytes += (size_t)obj_sz * HeapWordSize;
+
+ // This will happen if we are handling a humongous object that spans
+ // several heap regions.
+ if (obj_end > hr->end()) {
+ break;
+ }
+ // Find the next marked object after this one.
+ start = _bm->getNextMarkedWordAddress(obj_end, ntams);
+ }
+
+ // Mark the allocated-since-marking portion...
+ HeapWord* top = hr->top();
+ if (ntams < top) {
+ BitMap::idx_t start_idx = _cm->card_bitmap_index_for(ntams);
+ BitMap::idx_t end_idx = _cm->card_bitmap_index_for(top);
+
+ // Note: if we're looking at the last region in heap - top
+ // could be actually just beyond the end of the heap; end_idx
+ // will then correspond to a (non-existent) card that is also
+ // just beyond the heap.
+ if (_g1h->is_in_g1_reserved(top) && !_ct_bs->is_card_aligned(top)) {
+ // end of object is not card aligned - increment to cover
+ // all the cards spanned by the object
+ end_idx += 1;
+ }
+ _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */);
+
+ // This definitely means the region has live objects.
+ set_bit_for_region(hr);
+ }
+
+ // Update the live region bitmap.
+ if (marked_bytes > 0) {
+ set_bit_for_region(hr);
+ }
+
+ // Set the marked bytes for the current region so that
+ // it can be queried by a calling verification routine
+ _region_marked_bytes = marked_bytes;
+
+ return false;
+ }
+
+ size_t region_marked_bytes() const { return _region_marked_bytes; }
+};
+
+// Heap region closure used for verifying the counting data
+// that was accumulated concurrently and aggregated during
+// the remark pause. This closure is applied to the heap
+// regions during the STW cleanup pause.
+
+class VerifyLiveObjectDataHRClosure: public HeapRegionClosure {
+ G1CollectedHeap* _g1h;
+ G1ConcurrentMark* _cm;
+ CalcLiveObjectsClosure _calc_cl;
+ BitMap* _region_bm; // Region BM to be verified
+ BitMap* _card_bm; // Card BM to be verified
+
+ BitMap* _exp_region_bm; // Expected Region BM values
+ BitMap* _exp_card_bm; // Expected card BM values
+
+ int _failures;
+
+public:
+ VerifyLiveObjectDataHRClosure(G1CollectedHeap* g1h,
+ BitMap* region_bm,
+ BitMap* card_bm,
+ BitMap* exp_region_bm,
+ BitMap* exp_card_bm) :
+ _g1h(g1h), _cm(g1h->concurrent_mark()),
+ _calc_cl(_cm->nextMarkBitMap(), g1h, exp_region_bm, exp_card_bm),
+ _region_bm(region_bm), _card_bm(card_bm),
+ _exp_region_bm(exp_region_bm), _exp_card_bm(exp_card_bm),
+ _failures(0) { }
+
+ int failures() const { return _failures; }
+
+ bool doHeapRegion(HeapRegion* hr) {
+ int failures = 0;
+
+ // Call the CalcLiveObjectsClosure to walk the marking bitmap for
+ // this region and set the corresponding bits in the expected region
+ // and card bitmaps.
+ bool res = _calc_cl.doHeapRegion(hr);
+ assert(res == false, "should be continuing");
+
+ // Verify the marked bytes for this region.
+ size_t exp_marked_bytes = _calc_cl.region_marked_bytes();
+ size_t act_marked_bytes = hr->next_marked_bytes();
+
+ if (exp_marked_bytes > act_marked_bytes) {
+ if (hr->is_starts_humongous()) {
+ // For start_humongous regions, the size of the whole object will be
+ // in exp_marked_bytes.
+ HeapRegion* region = hr;
+ int num_regions;
+ for (num_regions = 0; region != NULL; num_regions++) {
+ region = _g1h->next_region_in_humongous(region);
+ }
+ if ((num_regions-1) * HeapRegion::GrainBytes >= exp_marked_bytes) {
+ failures += 1;
+ } else if (num_regions * HeapRegion::GrainBytes < exp_marked_bytes) {
+ failures += 1;
+ }
+ } else {
+ // We're not OK if expected marked bytes > actual marked bytes. It means
+ // we have missed accounting some objects during the actual marking.
+ failures += 1;
+ }
+ }
+
+ // Verify the bit, for this region, in the actual and expected
+ // (which was just calculated) region bit maps.
+ // We're not OK if the bit in the calculated expected region
+ // bitmap is set and the bit in the actual region bitmap is not.
+ BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
+
+ bool expected = _exp_region_bm->at(index);
+ bool actual = _region_bm->at(index);
+ if (expected && !actual) {
+ failures += 1;
+ }
+
+ // Verify that the card bit maps for the cards spanned by the current
+ // region match. We have an error if we have a set bit in the expected
+ // bit map and the corresponding bit in the actual bitmap is not set.
+
+ BitMap::idx_t start_idx = _cm->card_bitmap_index_for(hr->bottom());
+ BitMap::idx_t end_idx = _cm->card_bitmap_index_for(hr->top());
+
+ for (BitMap::idx_t i = start_idx; i < end_idx; i+=1) {
+ expected = _exp_card_bm->at(i);
+ actual = _card_bm->at(i);
+
+ if (expected && !actual) {
+ failures += 1;
+ }
+ }
+
+ _failures += failures;
+
+ // We could stop iteration over the heap when we
+ // find the first violating region by returning true.
+ return false;
+ }
+};
+
+class G1ParVerifyFinalCountTask: public AbstractGangTask {
+protected:
+ G1CollectedHeap* _g1h;
+ G1ConcurrentMark* _cm;
+ BitMap* _actual_region_bm;
+ BitMap* _actual_card_bm;
+
+ uint _n_workers;
+
+ BitMap* _expected_region_bm;
+ BitMap* _expected_card_bm;
+
+ int _failures;
+
+ HeapRegionClaimer _hrclaimer;
+
+public:
+ G1ParVerifyFinalCountTask(G1CollectedHeap* g1h,
+ BitMap* region_bm, BitMap* card_bm,
+ BitMap* expected_region_bm, BitMap* expected_card_bm)
+ : AbstractGangTask("G1 verify final counting"),
+ _g1h(g1h), _cm(_g1h->concurrent_mark()),
+ _actual_region_bm(region_bm), _actual_card_bm(card_bm),
+ _expected_region_bm(expected_region_bm), _expected_card_bm(expected_card_bm),
+ _failures(0),
+ _n_workers(_g1h->workers()->active_workers()), _hrclaimer(_n_workers) {
+ assert(VerifyDuringGC, "don't call this otherwise");
+ assert(_expected_card_bm->size() == _actual_card_bm->size(), "sanity");
+ assert(_expected_region_bm->size() == _actual_region_bm->size(), "sanity");
+ }
+
+ void work(uint worker_id) {
+ assert(worker_id < _n_workers, "invariant");
+
+ VerifyLiveObjectDataHRClosure verify_cl(_g1h,
+ _actual_region_bm, _actual_card_bm,
+ _expected_region_bm,
+ _expected_card_bm);
+
+ _g1h->heap_region_par_iterate(&verify_cl, worker_id, &_hrclaimer);
+
+ Atomic::add(verify_cl.failures(), &_failures);
+ }
+
+ int failures() const { return _failures; }
+};
+
+// Closure that finalizes the liveness counting data.
+// Used during the cleanup pause.
+// Sets the bits corresponding to the interval [NTAMS, top]
+// (which contains the implicitly live objects) in the
+// card liveness bitmap. Also sets the bit for each region,
+// containing live data, in the region liveness bitmap.
+
+class FinalCountDataUpdateClosure: public G1CMCountDataClosureBase {
+ public:
+ FinalCountDataUpdateClosure(G1CollectedHeap* g1h,
+ BitMap* region_bm,
+ BitMap* card_bm) :
+ G1CMCountDataClosureBase(g1h, region_bm, card_bm) { }
+
+ bool doHeapRegion(HeapRegion* hr) {
+ HeapWord* ntams = hr->next_top_at_mark_start();
+ HeapWord* top = hr->top();
+
+ assert(hr->bottom() <= ntams && ntams <= hr->end(), "Preconditions.");
+
+ // Mark the allocated-since-marking portion...
+ if (ntams < top) {
+ // This definitely means the region has live objects.
+ set_bit_for_region(hr);
+
+ // Now set the bits in the card bitmap for [ntams, top)
+ BitMap::idx_t start_idx = _cm->card_bitmap_index_for(ntams);
+ BitMap::idx_t end_idx = _cm->card_bitmap_index_for(top);
+
+ // Note: if we're looking at the last region in heap - top
+ // could be actually just beyond the end of the heap; end_idx
+ // will then correspond to a (non-existent) card that is also
+ // just beyond the heap.
+ if (_g1h->is_in_g1_reserved(top) && !_ct_bs->is_card_aligned(top)) {
+ // end of object is not card aligned - increment to cover
+ // all the cards spanned by the object
+ end_idx += 1;
+ }
+
+ assert(end_idx <= _card_bm->size(),
+ "oob: end_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT,
+ end_idx, _card_bm->size());
+ assert(start_idx < _card_bm->size(),
+ "oob: start_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT,
+ start_idx, _card_bm->size());
+
+ _cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */);
+ }
+
+ // Set the bit for the region if it contains live data
+ if (hr->next_marked_bytes() > 0) {
+ set_bit_for_region(hr);
+ }
+
+ return false;
+ }
+};
+
+class G1ParFinalCountTask: public AbstractGangTask {
+protected:
+ G1CollectedHeap* _g1h;
+ G1ConcurrentMark* _cm;
+ BitMap* _actual_region_bm;
+ BitMap* _actual_card_bm;
+
+ uint _n_workers;
+ HeapRegionClaimer _hrclaimer;
+
+public:
+ G1ParFinalCountTask(G1CollectedHeap* g1h, BitMap* region_bm, BitMap* card_bm)
+ : AbstractGangTask("G1 final counting"),
+ _g1h(g1h), _cm(_g1h->concurrent_mark()),
+ _actual_region_bm(region_bm), _actual_card_bm(card_bm),
+ _n_workers(_g1h->workers()->active_workers()), _hrclaimer(_n_workers) {
+ }
+
+ void work(uint worker_id) {
+ assert(worker_id < _n_workers, "invariant");
+
+ FinalCountDataUpdateClosure final_update_cl(_g1h,
+ _actual_region_bm,
+ _actual_card_bm);
+
+ _g1h->heap_region_par_iterate(&final_update_cl, worker_id, &_hrclaimer);
+ }
+};
+
+class G1NoteEndOfConcMarkClosure : public HeapRegionClosure {
+ G1CollectedHeap* _g1;
+ size_t _freed_bytes;
+ FreeRegionList* _local_cleanup_list;
+ uint _old_regions_removed;
+ uint _humongous_regions_removed;
+ HRRSCleanupTask* _hrrs_cleanup_task;
+
+public:
+ G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
+ FreeRegionList* local_cleanup_list,
+ HRRSCleanupTask* hrrs_cleanup_task) :
+ _g1(g1),
+ _freed_bytes(0),
+ _local_cleanup_list(local_cleanup_list),
+ _old_regions_removed(0),
+ _humongous_regions_removed(0),
+ _hrrs_cleanup_task(hrrs_cleanup_task) { }
+
+ size_t freed_bytes() { return _freed_bytes; }
+ const uint old_regions_removed() { return _old_regions_removed; }
+ const uint humongous_regions_removed() { return _humongous_regions_removed; }
+
+ bool doHeapRegion(HeapRegion *hr) {
+ if (hr->is_archive()) {
+ return false;
+ }
+ // We use a claim value of zero here because all regions
+ // were claimed with value 1 in the FinalCount task.
+ _g1->reset_gc_time_stamps(hr);
+ hr->note_end_of_marking();
+
+ if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young()) {
+ _freed_bytes += hr->used();
+ hr->set_containing_set(NULL);
+ if (hr->is_humongous()) {
+ _humongous_regions_removed++;
+ _g1->free_humongous_region(hr, _local_cleanup_list, true);
+ } else {
+ _old_regions_removed++;
+ _g1->free_region(hr, _local_cleanup_list, true);
+ }
+ } else {
+ hr->rem_set()->do_cleanup_work(_hrrs_cleanup_task);
+ }
+
+ return false;
+ }
+};
+
+class G1ParNoteEndTask: public AbstractGangTask {
+ friend class G1NoteEndOfConcMarkClosure;
+
+protected:
+ G1CollectedHeap* _g1h;
+ FreeRegionList* _cleanup_list;
+ HeapRegionClaimer _hrclaimer;
+
+public:
+ G1ParNoteEndTask(G1CollectedHeap* g1h, FreeRegionList* cleanup_list, uint n_workers) :
+ AbstractGangTask("G1 note end"), _g1h(g1h), _cleanup_list(cleanup_list), _hrclaimer(n_workers) {
+ }
+
+ void work(uint worker_id) {
+ FreeRegionList local_cleanup_list("Local Cleanup List");
+ HRRSCleanupTask hrrs_cleanup_task;
+ G1NoteEndOfConcMarkClosure g1_note_end(_g1h, &local_cleanup_list,
+ &hrrs_cleanup_task);
+ _g1h->heap_region_par_iterate(&g1_note_end, worker_id, &_hrclaimer);
+ assert(g1_note_end.complete(), "Shouldn't have yielded!");
+
+ // Now update the lists
+ _g1h->remove_from_old_sets(g1_note_end.old_regions_removed(), g1_note_end.humongous_regions_removed());
+ {
+ MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
+ _g1h->decrement_summary_bytes(g1_note_end.freed_bytes());
+
+ // If we iterate over the global cleanup list at the end of
+ // cleanup to do this printing we will not guarantee to only
+ // generate output for the newly-reclaimed regions (the list
+ // might not be empty at the beginning of cleanup; we might
+ // still be working on its previous contents). So we do the
+ // printing here, before we append the new regions to the global
+ // cleanup list.
+
+ G1HRPrinter* hr_printer = _g1h->hr_printer();
+ if (hr_printer->is_active()) {
+ FreeRegionListIterator iter(&local_cleanup_list);
+ while (iter.more_available()) {
+ HeapRegion* hr = iter.get_next();
+ hr_printer->cleanup(hr);
+ }
+ }
+
+ _cleanup_list->add_ordered(&local_cleanup_list);
+ assert(local_cleanup_list.is_empty(), "post-condition");
+
+ HeapRegionRemSet::finish_cleanup_task(&hrrs_cleanup_task);
+ }
+ }
+};
+
+void G1ConcurrentMark::cleanup() {
+ // world is stopped at this checkpoint
+ assert(SafepointSynchronize::is_at_safepoint(),
+ "world should be stopped");
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+ // If a full collection has happened, we shouldn't do this.
+ if (has_aborted()) {
+ g1h->collector_state()->set_mark_in_progress(false); // So bitmap clearing isn't confused
+ return;
+ }
+
+ g1h->verifier()->verify_region_sets_optional();
+
+ if (VerifyDuringGC) {
+ HandleMark hm; // handle scope
+ g1h->prepare_for_verify();
+ Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (before)");
+ }
+ g1h->verifier()->check_bitmaps("Cleanup Start");
+
+ G1CollectorPolicy* g1p = g1h->g1_policy();
+ g1p->record_concurrent_mark_cleanup_start();
+
+ double start = os::elapsedTime();
+
+ HeapRegionRemSet::reset_for_cleanup_tasks();
+
+ // Do counting once more with the world stopped for good measure.
+ G1ParFinalCountTask g1_par_count_task(g1h, &_region_bm, &_card_bm);
+
+ g1h->workers()->run_task(&g1_par_count_task);
+
+ if (VerifyDuringGC) {
+ // Verify that the counting data accumulated during marking matches
+ // that calculated by walking the marking bitmap.
+
+ // Bitmaps to hold expected values
+ BitMap expected_region_bm(_region_bm.size(), true);
+ BitMap expected_card_bm(_card_bm.size(), true);
+
+ G1ParVerifyFinalCountTask g1_par_verify_task(g1h,
+ &_region_bm,
+ &_card_bm,
+ &expected_region_bm,
+ &expected_card_bm);
+
+ g1h->workers()->run_task(&g1_par_verify_task);
+
+ guarantee(g1_par_verify_task.failures() == 0, "Unexpected accounting failures");
+ }
+
+ size_t start_used_bytes = g1h->used();
+ g1h->collector_state()->set_mark_in_progress(false);
+
+ double count_end = os::elapsedTime();
+ double this_final_counting_time = (count_end - start);
+ _total_counting_time += this_final_counting_time;
+
+ if (log_is_enabled(Trace, gc, liveness)) {
+ G1PrintRegionLivenessInfoClosure cl("Post-Marking");
+ _g1h->heap_region_iterate(&cl);
+ }
+
+ // Install newly created mark bitMap as "prev".
+ swapMarkBitMaps();
+
+ g1h->reset_gc_time_stamp();
+
+ uint n_workers = _g1h->workers()->active_workers();
+
+ // Note end of marking in all heap regions.
+ G1ParNoteEndTask g1_par_note_end_task(g1h, &_cleanup_list, n_workers);
+ g1h->workers()->run_task(&g1_par_note_end_task);
+ g1h->check_gc_time_stamps();
+
+ if (!cleanup_list_is_empty()) {
+ // The cleanup list is not empty, so we'll have to process it
+ // concurrently. Notify anyone else that might be wanting free
+ // regions that there will be more free regions coming soon.
+ g1h->set_free_regions_coming();
+ }
+
+ // call below, since it affects the metric by which we sort the heap
+ // regions.
+ if (G1ScrubRemSets) {
+ double rs_scrub_start = os::elapsedTime();
+ g1h->scrub_rem_set(&_region_bm, &_card_bm);
+ _total_rs_scrub_time += (os::elapsedTime() - rs_scrub_start);
+ }
+
+ // this will also free any regions totally full of garbage objects,
+ // and sort the regions.
+ g1h->g1_policy()->record_concurrent_mark_cleanup_end();
+
+ // Statistics.
+ double end = os::elapsedTime();
+ _cleanup_times.add((end - start) * 1000.0);
+
+ // Clean up will have freed any regions completely full of garbage.
+ // Update the soft reference policy with the new heap occupancy.
+ Universe::update_heap_info_at_gc();
+
+ if (VerifyDuringGC) {
+ HandleMark hm; // handle scope
+ g1h->prepare_for_verify();
+ Universe::verify(VerifyOption_G1UsePrevMarking, "During GC (after)");
+ }
+
+ g1h->verifier()->check_bitmaps("Cleanup End");
+
+ g1h->verifier()->verify_region_sets_optional();
+
+ // We need to make this be a "collection" so any collection pause that
+ // races with it goes around and waits for completeCleanup to finish.
+ g1h->increment_total_collections();
+
+ // Clean out dead classes and update Metaspace sizes.
+ if (ClassUnloadingWithConcurrentMark) {
+ ClassLoaderDataGraph::purge();
+ }
+ MetaspaceGC::compute_new_size();
+
+ // We reclaimed old regions so we should calculate the sizes to make
+ // sure we update the old gen/space data.
+ g1h->g1mm()->update_sizes();
+ g1h->allocation_context_stats().update_after_mark();
+
+ g1h->trace_heap_after_concurrent_cycle();
+}
+
+void G1ConcurrentMark::completeCleanup() {
+ if (has_aborted()) return;
+
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+ _cleanup_list.verify_optional();
+ FreeRegionList tmp_free_list("Tmp Free List");
+
+ log_develop_trace(gc, freelist)("G1ConcRegionFreeing [complete cleanup] : "
+ "cleanup list has %u entries",
+ _cleanup_list.length());
+
+ // No one else should be accessing the _cleanup_list at this point,
+ // so it is not necessary to take any locks
+ while (!_cleanup_list.is_empty()) {
+ HeapRegion* hr = _cleanup_list.remove_region(true /* from_head */);
+ assert(hr != NULL, "Got NULL from a non-empty list");
+ hr->par_clear();
+ tmp_free_list.add_ordered(hr);
+
+ // Instead of adding one region at a time to the secondary_free_list,
+ // we accumulate them in the local list and move them a few at a
+ // time. This also cuts down on the number of notify_all() calls
+ // we do during this process. We'll also append the local list when
+ // _cleanup_list is empty (which means we just removed the last
+ // region from the _cleanup_list).
+ if ((tmp_free_list.length() % G1SecondaryFreeListAppendLength == 0) ||
+ _cleanup_list.is_empty()) {
+ log_develop_trace(gc, freelist)("G1ConcRegionFreeing [complete cleanup] : "
+ "appending %u entries to the secondary_free_list, "
+ "cleanup list still has %u entries",
+ tmp_free_list.length(),
+ _cleanup_list.length());
+
+ {
+ MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag);
+ g1h->secondary_free_list_add(&tmp_free_list);
+ SecondaryFreeList_lock->notify_all();
+ }
+#ifndef PRODUCT
+ if (G1StressConcRegionFreeing) {
+ for (uintx i = 0; i < G1StressConcRegionFreeingDelayMillis; ++i) {
+ os::sleep(Thread::current(), (jlong) 1, false);
+ }
+ }
+#endif
+ }
+ }
+ assert(tmp_free_list.is_empty(), "post-condition");
+}
+
+// Supporting Object and Oop closures for reference discovery
+// and processing in during marking
+
+bool G1CMIsAliveClosure::do_object_b(oop obj) {
+ HeapWord* addr = (HeapWord*)obj;
+ return addr != NULL &&
+ (!_g1->is_in_g1_reserved(addr) || !_g1->is_obj_ill(obj));
+}
+
+// 'Keep Alive' oop closure used by both serial parallel reference processing.
+// Uses the G1CMTask associated with a worker thread (for serial reference
+// processing the G1CMTask for worker 0 is used) to preserve (mark) and
+// trace referent objects.
+//
+// Using the G1CMTask and embedded local queues avoids having the worker
+// threads operating on the global mark stack. This reduces the risk
+// of overflowing the stack - which we would rather avoid at this late
+// state. Also using the tasks' local queues removes the potential
+// of the workers interfering with each other that could occur if
+// operating on the global stack.
+
+class G1CMKeepAliveAndDrainClosure: public OopClosure {
+ G1ConcurrentMark* _cm;
+ G1CMTask* _task;
+ int _ref_counter_limit;
+ int _ref_counter;
+ bool _is_serial;
+ public:
+ G1CMKeepAliveAndDrainClosure(G1ConcurrentMark* cm, G1CMTask* task, bool is_serial) :
+ _cm(cm), _task(task), _is_serial(is_serial),
+ _ref_counter_limit(G1RefProcDrainInterval) {
+ assert(_ref_counter_limit > 0, "sanity");
+ assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code");
+ _ref_counter = _ref_counter_limit;
+ }
+
+ virtual void do_oop(narrowOop* p) { do_oop_work(p); }
+ virtual void do_oop( oop* p) { do_oop_work(p); }
+
+ template <class T> void do_oop_work(T* p) {
+ if (!_cm->has_overflown()) {
+ oop obj = oopDesc::load_decode_heap_oop(p);
+ _task->deal_with_reference(obj);
+ _ref_counter--;
+
+ if (_ref_counter == 0) {
+ // We have dealt with _ref_counter_limit references, pushing them
+ // and objects reachable from them on to the local stack (and
+ // possibly the global stack). Call G1CMTask::do_marking_step() to
+ // process these entries.
+ //
+ // We call G1CMTask::do_marking_step() in a loop, which we'll exit if
+ // there's nothing more to do (i.e. we're done with the entries that
+ // were pushed as a result of the G1CMTask::deal_with_reference() calls
+ // above) or we overflow.
+ //
+ // Note: G1CMTask::do_marking_step() can set the G1CMTask::has_aborted()
+ // flag while there may still be some work to do. (See the comment at
+ // the beginning of G1CMTask::do_marking_step() for those conditions -
+ // one of which is reaching the specified time target.) It is only
+ // when G1CMTask::do_marking_step() returns without setting the
+ // has_aborted() flag that the marking step has completed.
+ do {
+ double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
+ _task->do_marking_step(mark_step_duration_ms,
+ false /* do_termination */,
+ _is_serial);
+ } while (_task->has_aborted() && !_cm->has_overflown());
+ _ref_counter = _ref_counter_limit;
+ }
+ }
+ }
+};
+
+// 'Drain' oop closure used by both serial and parallel reference processing.
+// Uses the G1CMTask associated with a given worker thread (for serial
+// reference processing the G1CMtask for worker 0 is used). Calls the
+// do_marking_step routine, with an unbelievably large timeout value,
+// to drain the marking data structures of the remaining entries
+// added by the 'keep alive' oop closure above.
+
+class G1CMDrainMarkingStackClosure: public VoidClosure {
+ G1ConcurrentMark* _cm;
+ G1CMTask* _task;
+ bool _is_serial;
+ public:
+ G1CMDrainMarkingStackClosure(G1ConcurrentMark* cm, G1CMTask* task, bool is_serial) :
+ _cm(cm), _task(task), _is_serial(is_serial) {
+ assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code");
+ }
+
+ void do_void() {
+ do {
+ // We call G1CMTask::do_marking_step() to completely drain the local
+ // and global marking stacks of entries pushed by the 'keep alive'
+ // oop closure (an instance of G1CMKeepAliveAndDrainClosure above).
+ //
+ // G1CMTask::do_marking_step() is called in a loop, which we'll exit
+ // if there's nothing more to do (i.e. we've completely drained the
+ // entries that were pushed as a a result of applying the 'keep alive'
+ // closure to the entries on the discovered ref lists) or we overflow
+ // the global marking stack.
+ //
+ // Note: G1CMTask::do_marking_step() can set the G1CMTask::has_aborted()
+ // flag while there may still be some work to do. (See the comment at
+ // the beginning of G1CMTask::do_marking_step() for those conditions -
+ // one of which is reaching the specified time target.) It is only
+ // when G1CMTask::do_marking_step() returns without setting the
+ // has_aborted() flag that the marking step has completed.
+
+ _task->do_marking_step(1000000000.0 /* something very large */,
+ true /* do_termination */,
+ _is_serial);
+ } while (_task->has_aborted() && !_cm->has_overflown());
+ }
+};
+
+// Implementation of AbstractRefProcTaskExecutor for parallel
+// reference processing at the end of G1 concurrent marking
+
+class G1CMRefProcTaskExecutor: public AbstractRefProcTaskExecutor {
+private:
+ G1CollectedHeap* _g1h;
+ G1ConcurrentMark* _cm;
+ WorkGang* _workers;
+ uint _active_workers;
+
+public:
+ G1CMRefProcTaskExecutor(G1CollectedHeap* g1h,
+ G1ConcurrentMark* cm,
+ WorkGang* workers,
+ uint n_workers) :
+ _g1h(g1h), _cm(cm),
+ _workers(workers), _active_workers(n_workers) { }
+
+ // Executes the given task using concurrent marking worker threads.
+ virtual void execute(ProcessTask& task);
+ virtual void execute(EnqueueTask& task);
+};
+
+class G1CMRefProcTaskProxy: public AbstractGangTask {
+ typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask;
+ ProcessTask& _proc_task;
+ G1CollectedHeap* _g1h;
+ G1ConcurrentMark* _cm;
+
+public:
+ G1CMRefProcTaskProxy(ProcessTask& proc_task,
+ G1CollectedHeap* g1h,
+ G1ConcurrentMark* cm) :
+ AbstractGangTask("Process reference objects in parallel"),
+ _proc_task(proc_task), _g1h(g1h), _cm(cm) {
+ ReferenceProcessor* rp = _g1h->ref_processor_cm();
+ assert(rp->processing_is_mt(), "shouldn't be here otherwise");
+ }
+
+ virtual void work(uint worker_id) {
+ ResourceMark rm;
+ HandleMark hm;
+ G1CMTask* task = _cm->task(worker_id);
+ G1CMIsAliveClosure g1_is_alive(_g1h);
+ G1CMKeepAliveAndDrainClosure g1_par_keep_alive(_cm, task, false /* is_serial */);
+ G1CMDrainMarkingStackClosure g1_par_drain(_cm, task, false /* is_serial */);
+
+ _proc_task.work(worker_id, g1_is_alive, g1_par_keep_alive, g1_par_drain);
+ }
+};
+
+void G1CMRefProcTaskExecutor::execute(ProcessTask& proc_task) {
+ assert(_workers != NULL, "Need parallel worker threads.");
+ assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT");
+
+ G1CMRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _cm);
+
+ // We need to reset the concurrency level before each
+ // proxy task execution, so that the termination protocol
+ // and overflow handling in G1CMTask::do_marking_step() knows
+ // how many workers to wait for.
+ _cm->set_concurrency(_active_workers);
+ _workers->run_task(&proc_task_proxy);
+}
+
+class G1CMRefEnqueueTaskProxy: public AbstractGangTask {
+ typedef AbstractRefProcTaskExecutor::EnqueueTask EnqueueTask;
+ EnqueueTask& _enq_task;
+
+public:
+ G1CMRefEnqueueTaskProxy(EnqueueTask& enq_task) :
+ AbstractGangTask("Enqueue reference objects in parallel"),
+ _enq_task(enq_task) { }
+
+ virtual void work(uint worker_id) {
+ _enq_task.work(worker_id);
+ }
+};
+
+void G1CMRefProcTaskExecutor::execute(EnqueueTask& enq_task) {
+ assert(_workers != NULL, "Need parallel worker threads.");
+ assert(_g1h->ref_processor_cm()->processing_is_mt(), "processing is not MT");
+
+ G1CMRefEnqueueTaskProxy enq_task_proxy(enq_task);
+
+ // Not strictly necessary but...
+ //
+ // We need to reset the concurrency level before each
+ // proxy task execution, so that the termination protocol
+ // and overflow handling in G1CMTask::do_marking_step() knows
+ // how many workers to wait for.
+ _cm->set_concurrency(_active_workers);
+ _workers->run_task(&enq_task_proxy);
+}
+
+void G1ConcurrentMark::weakRefsWorkParallelPart(BoolObjectClosure* is_alive, bool purged_classes) {
+ G1CollectedHeap::heap()->parallel_cleaning(is_alive, true, true, purged_classes);
+}
+
+void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
+ if (has_overflown()) {
+ // Skip processing the discovered references if we have
+ // overflown the global marking stack. Reference objects
+ // only get discovered once so it is OK to not
+ // de-populate the discovered reference lists. We could have,
+ // but the only benefit would be that, when marking restarts,
+ // less reference objects are discovered.
+ return;
+ }
+
+ ResourceMark rm;
+ HandleMark hm;
+
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+ // Is alive closure.
+ G1CMIsAliveClosure g1_is_alive(g1h);
+
+ // Inner scope to exclude the cleaning of the string and symbol
+ // tables from the displayed time.
+ {
+ GCTraceTime(Debug, gc) trace("GC Ref Proc", g1h->gc_timer_cm());
+
+ ReferenceProcessor* rp = g1h->ref_processor_cm();
+
+ // See the comment in G1CollectedHeap::ref_processing_init()
+ // about how reference processing currently works in G1.
+
+ // Set the soft reference policy
+ rp->setup_policy(clear_all_soft_refs);
+ assert(_markStack.isEmpty(), "mark stack should be empty");
+
+ // Instances of the 'Keep Alive' and 'Complete GC' closures used
+ // in serial reference processing. Note these closures are also
+ // used for serially processing (by the the current thread) the
+ // JNI references during parallel reference processing.
+ //
+ // These closures do not need to synchronize with the worker
+ // threads involved in parallel reference processing as these
+ // instances are executed serially by the current thread (e.g.
+ // reference processing is not multi-threaded and is thus
+ // performed by the current thread instead of a gang worker).
+ //
+ // The gang tasks involved in parallel reference processing create
+ // their own instances of these closures, which do their own
+ // synchronization among themselves.
+ G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0), true /* is_serial */);
+ G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), true /* is_serial */);
+
+ // We need at least one active thread. If reference processing
+ // is not multi-threaded we use the current (VMThread) thread,
+ // otherwise we use the work gang from the G1CollectedHeap and
+ // we utilize all the worker threads we can.
+ bool processing_is_mt = rp->processing_is_mt();
+ uint active_workers = (processing_is_mt ? g1h->workers()->active_workers() : 1U);
+ active_workers = MAX2(MIN2(active_workers, _max_worker_id), 1U);
+
+ // Parallel processing task executor.
+ G1CMRefProcTaskExecutor par_task_executor(g1h, this,
+ g1h->workers(), active_workers);
+ AbstractRefProcTaskExecutor* executor = (processing_is_mt ? &par_task_executor : NULL);
+
+ // Set the concurrency level. The phase was already set prior to
+ // executing the remark task.
+ set_concurrency(active_workers);
+
+ // Set the degree of MT processing here. If the discovery was done MT,
+ // the number of threads involved during discovery could differ from
+ // the number of active workers. This is OK as long as the discovered
+ // Reference lists are balanced (see balance_all_queues() and balance_queues()).
+ rp->set_active_mt_degree(active_workers);
+
+ // Process the weak references.
+ const ReferenceProcessorStats& stats =
+ rp->process_discovered_references(&g1_is_alive,
+ &g1_keep_alive,
+ &g1_drain_mark_stack,
+ executor,
+ g1h->gc_timer_cm());
+ g1h->gc_tracer_cm()->report_gc_reference_stats(stats);
+
+ // The do_oop work routines of the keep_alive and drain_marking_stack
+ // oop closures will set the has_overflown flag if we overflow the
+ // global marking stack.
+
+ assert(_markStack.overflow() || _markStack.isEmpty(),
+ "mark stack should be empty (unless it overflowed)");
+
+ if (_markStack.overflow()) {
+ // This should have been done already when we tried to push an
+ // entry on to the global mark stack. But let's do it again.
+ set_has_overflown();
+ }
+
+ assert(rp->num_q() == active_workers, "why not");
+
+ rp->enqueue_discovered_references(executor);
+
+ rp->verify_no_references_recorded();
+ assert(!rp->discovery_enabled(), "Post condition");
+ }
+
+ if (has_overflown()) {
+ // We can not trust g1_is_alive if the marking stack overflowed
+ return;
+ }
+
+ assert(_markStack.isEmpty(), "Marking should have completed");
+
+ // Unload Klasses, String, Symbols, Code Cache, etc.
+ {
+ GCTraceTime(Debug, gc) trace("Unloading", g1h->gc_timer_cm());
+
+ if (ClassUnloadingWithConcurrentMark) {
+ bool purged_classes;
+
+ {
+ GCTraceTime(Trace, gc) trace("System Dictionary Unloading", g1h->gc_timer_cm());
+ purged_classes = SystemDictionary::do_unloading(&g1_is_alive, false /* Defer klass cleaning */);
+ }
+
+ {
+ GCTraceTime(Trace, gc) trace("Parallel Unloading", g1h->gc_timer_cm());
+ weakRefsWorkParallelPart(&g1_is_alive, purged_classes);
+ }
+ }
+
+ if (G1StringDedup::is_enabled()) {
+ GCTraceTime(Trace, gc) trace("String Deduplication Unlink", g1h->gc_timer_cm());
+ G1StringDedup::unlink(&g1_is_alive);
+ }
+ }
+}
+
+void G1ConcurrentMark::swapMarkBitMaps() {
+ G1CMBitMapRO* temp = _prevMarkBitMap;
+ _prevMarkBitMap = (G1CMBitMapRO*)_nextMarkBitMap;
+ _nextMarkBitMap = (G1CMBitMap*) temp;
+}
+
+// Closure for marking entries in SATB buffers.
+class G1CMSATBBufferClosure : public SATBBufferClosure {
+private:
+ G1CMTask* _task;
+ G1CollectedHeap* _g1h;
+
+ // This is very similar to G1CMTask::deal_with_reference, but with
+ // more relaxed requirements for the argument, so this must be more
+ // circumspect about treating the argument as an object.
+ void do_entry(void* entry) const {
+ _task->increment_refs_reached();
+ HeapRegion* hr = _g1h->heap_region_containing(entry);
+ if (entry < hr->next_top_at_mark_start()) {
+ // Until we get here, we don't know whether entry refers to a valid
+ // object; it could instead have been a stale reference.
+ oop obj = static_cast<oop>(entry);
+ assert(obj->is_oop(true /* ignore mark word */),
+ "Invalid oop in SATB buffer: " PTR_FORMAT, p2i(obj));
+ _task->make_reference_grey(obj, hr);
+ }
+ }
+
+public:
+ G1CMSATBBufferClosure(G1CMTask* task, G1CollectedHeap* g1h)
+ : _task(task), _g1h(g1h) { }
+
+ virtual void do_buffer(void** buffer, size_t size) {
+ for (size_t i = 0; i < size; ++i) {
+ do_entry(buffer[i]);
+ }
+ }
+};
+
+class G1RemarkThreadsClosure : public ThreadClosure {
+ G1CMSATBBufferClosure _cm_satb_cl;
+ G1CMOopClosure _cm_cl;
+ MarkingCodeBlobClosure _code_cl;
+ int _thread_parity;
+
+ public:
+ G1RemarkThreadsClosure(G1CollectedHeap* g1h, G1CMTask* task) :
+ _cm_satb_cl(task, g1h),
+ _cm_cl(g1h, g1h->concurrent_mark(), task),
+ _code_cl(&_cm_cl, !CodeBlobToOopClosure::FixRelocations),
+ _thread_parity(Threads::thread_claim_parity()) {}
+
+ void do_thread(Thread* thread) {
+ if (thread->is_Java_thread()) {
+ if (thread->claim_oops_do(true, _thread_parity)) {
+ JavaThread* jt = (JavaThread*)thread;
+
+ // In theory it should not be neccessary to explicitly walk the nmethods to find roots for concurrent marking
+ // however the liveness of oops reachable from nmethods have very complex lifecycles:
+ // * Alive if on the stack of an executing method
+ // * Weakly reachable otherwise
+ // Some objects reachable from nmethods, such as the class loader (or klass_holder) of the receiver should be
+ // live by the SATB invariant but other oops recorded in nmethods may behave differently.
+ jt->nmethods_do(&_code_cl);
+
+ jt->satb_mark_queue().apply_closure_and_empty(&_cm_satb_cl);
+ }
+ } else if (thread->is_VM_thread()) {
+ if (thread->claim_oops_do(true, _thread_parity)) {
+ JavaThread::satb_mark_queue_set().shared_satb_queue()->apply_closure_and_empty(&_cm_satb_cl);
+ }
+ }
+ }
+};
+
+class G1CMRemarkTask: public AbstractGangTask {
+private:
+ G1ConcurrentMark* _cm;
+public:
+ void work(uint worker_id) {
+ // Since all available tasks are actually started, we should
+ // only proceed if we're supposed to be active.
+ if (worker_id < _cm->active_tasks()) {
+ G1CMTask* task = _cm->task(worker_id);
+ task->record_start_time();
+ {
+ ResourceMark rm;
+ HandleMark hm;
+
+ G1RemarkThreadsClosure threads_f(G1CollectedHeap::heap(), task);
+ Threads::threads_do(&threads_f);
+ }
+
+ do {
+ task->do_marking_step(1000000000.0 /* something very large */,
+ true /* do_termination */,
+ false /* is_serial */);
+ } while (task->has_aborted() && !_cm->has_overflown());
+ // If we overflow, then we do not want to restart. We instead
+ // want to abort remark and do concurrent marking again.
+ task->record_end_time();
+ }
+ }
+
+ G1CMRemarkTask(G1ConcurrentMark* cm, uint active_workers) :
+ AbstractGangTask("Par Remark"), _cm(cm) {
+ _cm->terminator()->reset_for_reuse(active_workers);
+ }
+};
+
+void G1ConcurrentMark::checkpointRootsFinalWork() {
+ ResourceMark rm;
+ HandleMark hm;
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+ GCTraceTime(Debug, gc) trace("Finalize Marking", g1h->gc_timer_cm());
+
+ g1h->ensure_parsability(false);
+
+ // this is remark, so we'll use up all active threads
+ uint active_workers = g1h->workers()->active_workers();
+ set_concurrency_and_phase(active_workers, false /* concurrent */);
+ // Leave _parallel_marking_threads at it's
+ // value originally calculated in the G1ConcurrentMark
+ // constructor and pass values of the active workers
+ // through the gang in the task.
+
+ {
+ StrongRootsScope srs(active_workers);
+
+ G1CMRemarkTask remarkTask(this, active_workers);
+ // We will start all available threads, even if we decide that the
+ // active_workers will be fewer. The extra ones will just bail out
+ // immediately.
+ g1h->workers()->run_task(&remarkTask);
+ }
+
+ SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
+ guarantee(has_overflown() ||
+ satb_mq_set.completed_buffers_num() == 0,
+ "Invariant: has_overflown = %s, num buffers = %d",
+ BOOL_TO_STR(has_overflown()),
+ satb_mq_set.completed_buffers_num());
+
+ print_stats();
+}
+
+void G1ConcurrentMark::clearRangePrevBitmap(MemRegion mr) {
+ // Note we are overriding the read-only view of the prev map here, via
+ // the cast.
+ ((G1CMBitMap*)_prevMarkBitMap)->clearRange(mr);
+}
+
+HeapRegion*
+G1ConcurrentMark::claim_region(uint worker_id) {
+ // "checkpoint" the finger
+ HeapWord* finger = _finger;
+
+ // _heap_end will not change underneath our feet; it only changes at
+ // yield points.
+ while (finger < _heap_end) {
+ assert(_g1h->is_in_g1_reserved(finger), "invariant");
+
+ HeapRegion* curr_region = _g1h->heap_region_containing(finger);
+
+ // Above heap_region_containing may return NULL as we always scan claim
+ // until the end of the heap. In this case, just jump to the next region.
+ HeapWord* end = curr_region != NULL ? curr_region->end() : finger + HeapRegion::GrainWords;
+
+ // Is the gap between reading the finger and doing the CAS too long?
+ HeapWord* res = (HeapWord*) Atomic::cmpxchg_ptr(end, &_finger, finger);
+ if (res == finger && curr_region != NULL) {
+ // we succeeded
+ HeapWord* bottom = curr_region->bottom();
+ HeapWord* limit = curr_region->next_top_at_mark_start();
+
+ // notice that _finger == end cannot be guaranteed here since,
+ // someone else might have moved the finger even further
+ assert(_finger >= end, "the finger should have moved forward");
+
+ if (limit > bottom) {
+ return curr_region;
+ } else {
+ assert(limit == bottom,
+ "the region limit should be at bottom");
+ // we return NULL and the caller should try calling
+ // claim_region() again.
+ return NULL;
+ }
+ } else {
+ assert(_finger > finger, "the finger should have moved forward");
+ // read it again
+ finger = _finger;
+ }
+ }
+
+ return NULL;
+}
+
+#ifndef PRODUCT
+class VerifyNoCSetOops VALUE_OBJ_CLASS_SPEC {
+private:
+ G1CollectedHeap* _g1h;
+ const char* _phase;
+ int _info;
+
+public:
+ VerifyNoCSetOops(const char* phase, int info = -1) :
+ _g1h(G1CollectedHeap::heap()),
+ _phase(phase),
+ _info(info)
+ { }
+
+ void operator()(oop obj) const {
+ guarantee(obj->is_oop(),
+ "Non-oop " PTR_FORMAT ", phase: %s, info: %d",
+ p2i(obj), _phase, _info);
+ guarantee(!_g1h->obj_in_cs(obj),
+ "obj: " PTR_FORMAT " in CSet, phase: %s, info: %d",
+ p2i(obj), _phase, _info);
+ }
+};
+
+void G1ConcurrentMark::verify_no_cset_oops() {
+ assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
+ if (!G1CollectedHeap::heap()->collector_state()->mark_in_progress()) {
+ return;
+ }
+
+ // Verify entries on the global mark stack
+ _markStack.iterate(VerifyNoCSetOops("Stack"));
+
+ // Verify entries on the task queues
+ for (uint i = 0; i < _max_worker_id; ++i) {
+ G1CMTaskQueue* queue = _task_queues->queue(i);
+ queue->iterate(VerifyNoCSetOops("Queue", i));
+ }
+
+ // Verify the global finger
+ HeapWord* global_finger = finger();
+ if (global_finger != NULL && global_finger < _heap_end) {
+ // Since we always iterate over all regions, we might get a NULL HeapRegion
+ // here.
+ HeapRegion* global_hr = _g1h->heap_region_containing(global_finger);
+ guarantee(global_hr == NULL || global_finger == global_hr->bottom(),
+ "global finger: " PTR_FORMAT " region: " HR_FORMAT,
+ p2i(global_finger), HR_FORMAT_PARAMS(global_hr));
+ }
+
+ // Verify the task fingers
+ assert(parallel_marking_threads() <= _max_worker_id, "sanity");
+ for (uint i = 0; i < parallel_marking_threads(); ++i) {
+ G1CMTask* task = _tasks[i];
+ HeapWord* task_finger = task->finger();
+ if (task_finger != NULL && task_finger < _heap_end) {
+ // See above note on the global finger verification.
+ HeapRegion* task_hr = _g1h->heap_region_containing(task_finger);
+ guarantee(task_hr == NULL || task_finger == task_hr->bottom() ||
+ !task_hr->in_collection_set(),
+ "task finger: " PTR_FORMAT " region: " HR_FORMAT,
+ p2i(task_finger), HR_FORMAT_PARAMS(task_hr));
+ }
+ }
+}
+#endif // PRODUCT
+
+// Aggregate the counting data that was constructed concurrently
+// with marking.
+class AggregateCountDataHRClosure: public HeapRegionClosure {
+ G1CollectedHeap* _g1h;
+ G1ConcurrentMark* _cm;
+ CardTableModRefBS* _ct_bs;
+ BitMap* _cm_card_bm;
+ uint _max_worker_id;
+
+ public:
+ AggregateCountDataHRClosure(G1CollectedHeap* g1h,
+ BitMap* cm_card_bm,
+ uint max_worker_id) :
+ _g1h(g1h), _cm(g1h->concurrent_mark()),
+ _ct_bs(barrier_set_cast<CardTableModRefBS>(g1h->barrier_set())),
+ _cm_card_bm(cm_card_bm), _max_worker_id(max_worker_id) { }
+
+ bool doHeapRegion(HeapRegion* hr) {
+ HeapWord* start = hr->bottom();
+ HeapWord* limit = hr->next_top_at_mark_start();
+ HeapWord* end = hr->end();
+
+ assert(start <= limit && limit <= hr->top() && hr->top() <= hr->end(),
+ "Preconditions not met - "
+ "start: " PTR_FORMAT ", limit: " PTR_FORMAT ", "
+ "top: " PTR_FORMAT ", end: " PTR_FORMAT,
+ p2i(start), p2i(limit), p2i(hr->top()), p2i(hr->end()));
+
+ assert(hr->next_marked_bytes() == 0, "Precondition");
+
+ if (start == limit) {
+ // NTAMS of this region has not been set so nothing to do.
+ return false;
+ }
+
+ // 'start' should be in the heap.
+ assert(_g1h->is_in_g1_reserved(start) && _ct_bs->is_card_aligned(start), "sanity");
+ // 'end' *may* be just beyond the end of the heap (if hr is the last region)
+ assert(!_g1h->is_in_g1_reserved(end) || _ct_bs->is_card_aligned(end), "sanity");
+
+ BitMap::idx_t start_idx = _cm->card_bitmap_index_for(start);
+ BitMap::idx_t limit_idx = _cm->card_bitmap_index_for(limit);
+ BitMap::idx_t end_idx = _cm->card_bitmap_index_for(end);
+
+ // If ntams is not card aligned then we bump card bitmap index
+ // for limit so that we get the all the cards spanned by
+ // the object ending at ntams.
+ // Note: if this is the last region in the heap then ntams
+ // could be actually just beyond the end of the the heap;
+ // limit_idx will then correspond to a (non-existent) card
+ // that is also outside the heap.
+ if (_g1h->is_in_g1_reserved(limit) && !_ct_bs->is_card_aligned(limit)) {
+ limit_idx += 1;
+ }
+
+ assert(limit_idx <= end_idx, "or else use atomics");
+
+ // Aggregate the "stripe" in the count data associated with hr.
+ uint hrm_index = hr->hrm_index();
+ size_t marked_bytes = 0;
+
+ for (uint i = 0; i < _max_worker_id; i += 1) {
+ size_t* marked_bytes_array = _cm->count_marked_bytes_array_for(i);
+ BitMap* task_card_bm = _cm->count_card_bitmap_for(i);
+
+ // Fetch the marked_bytes in this region for task i and
+ // add it to the running total for this region.
+ marked_bytes += marked_bytes_array[hrm_index];
+
+ // Now union the bitmaps[0,max_worker_id)[start_idx..limit_idx)
+ // into the global card bitmap.
+ BitMap::idx_t scan_idx = task_card_bm->get_next_one_offset(start_idx, limit_idx);
+
+ while (scan_idx < limit_idx) {
+ assert(task_card_bm->at(scan_idx) == true, "should be");
+ _cm_card_bm->set_bit(scan_idx);
+ assert(_cm_card_bm->at(scan_idx) == true, "should be");
+
+ // BitMap::get_next_one_offset() can handle the case when
+ // its left_offset parameter is greater than its right_offset
+ // parameter. It does, however, have an early exit if
+ // left_offset == right_offset. So let's limit the value
+ // passed in for left offset here.
+ BitMap::idx_t next_idx = MIN2(scan_idx + 1, limit_idx);
+ scan_idx = task_card_bm->get_next_one_offset(next_idx, limit_idx);
+ }
+ }
+
+ // Update the marked bytes for this region.
+ hr->add_to_marked_bytes(marked_bytes);
+
+ // Next heap region
+ return false;
+ }
+};
+
+class G1AggregateCountDataTask: public AbstractGangTask {
+protected:
+ G1CollectedHeap* _g1h;
+ G1ConcurrentMark* _cm;
+ BitMap* _cm_card_bm;
+ uint _max_worker_id;
+ uint _active_workers;
+ HeapRegionClaimer _hrclaimer;
+
+public:
+ G1AggregateCountDataTask(G1CollectedHeap* g1h,
+ G1ConcurrentMark* cm,
+ BitMap* cm_card_bm,
+ uint max_worker_id,
+ uint n_workers) :
+ AbstractGangTask("Count Aggregation"),
+ _g1h(g1h), _cm(cm), _cm_card_bm(cm_card_bm),
+ _max_worker_id(max_worker_id),
+ _active_workers(n_workers),
+ _hrclaimer(_active_workers) {
+ }
+
+ void work(uint worker_id) {
+ AggregateCountDataHRClosure cl(_g1h, _cm_card_bm, _max_worker_id);
+
+ _g1h->heap_region_par_iterate(&cl, worker_id, &_hrclaimer);
+ }
+};
+
+
+void G1ConcurrentMark::aggregate_count_data() {
+ uint n_workers = _g1h->workers()->active_workers();
+
+ G1AggregateCountDataTask g1_par_agg_task(_g1h, this, &_card_bm,
+ _max_worker_id, n_workers);
+
+ _g1h->workers()->run_task(&g1_par_agg_task);
+}
+
+// Clear the per-worker arrays used to store the per-region counting data
+void G1ConcurrentMark::clear_all_count_data() {
+ // Clear the global card bitmap - it will be filled during
+ // liveness count aggregation (during remark) and the
+ // final counting task.
+ _card_bm.clear();
+
+ // Clear the global region bitmap - it will be filled as part
+ // of the final counting task.
+ _region_bm.clear();
+
+ uint max_regions = _g1h->max_regions();
+ assert(_max_worker_id > 0, "uninitialized");
+
+ for (uint i = 0; i < _max_worker_id; i += 1) {
+ BitMap* task_card_bm = count_card_bitmap_for(i);
+ size_t* marked_bytes_array = count_marked_bytes_array_for(i);
+
+ assert(task_card_bm->size() == _card_bm.size(), "size mismatch");
+ assert(marked_bytes_array != NULL, "uninitialized");
+
+ memset(marked_bytes_array, 0, (size_t) max_regions * sizeof(size_t));
+ task_card_bm->clear();
+ }
+}
+
+void G1ConcurrentMark::print_stats() {
+ if (!log_is_enabled(Debug, gc, stats)) {
+ return;
+ }
+ log_debug(gc, stats)("---------------------------------------------------------------------");
+ for (size_t i = 0; i < _active_tasks; ++i) {
+ _tasks[i]->print_stats();
+ log_debug(gc, stats)("---------------------------------------------------------------------");
+ }
+}
+
+// abandon current marking iteration due to a Full GC
+void G1ConcurrentMark::abort() {
+ if (!cmThread()->during_cycle() || _has_aborted) {
+ // We haven't started a concurrent cycle or we have already aborted it. No need to do anything.
+ return;
+ }
+
+ // Clear all marks in the next bitmap for the next marking cycle. This will allow us to skip the next
+ // concurrent bitmap clearing.
+ _nextMarkBitMap->clearAll();
+
+ // Note we cannot clear the previous marking bitmap here
+ // since VerifyDuringGC verifies the objects marked during
+ // a full GC against the previous bitmap.
+
+ // Clear the liveness counting data
+ clear_all_count_data();
+ // Empty mark stack
+ reset_marking_state();
+ for (uint i = 0; i < _max_worker_id; ++i) {
+ _tasks[i]->clear_region_fields();
+ }
+ _first_overflow_barrier_sync.abort();
+ _second_overflow_barrier_sync.abort();
+ _has_aborted = true;
+
+ SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
+ satb_mq_set.abandon_partial_marking();
+ // This can be called either during or outside marking, we'll read
+ // the expected_active value from the SATB queue set.
+ satb_mq_set.set_active_all_threads(
+ false, /* new active value */
+ satb_mq_set.is_active() /* expected_active */);
+
+ _g1h->trace_heap_after_concurrent_cycle();
+
+ // Close any open concurrent phase timing
+ register_concurrent_phase_end();
+
+ _g1h->register_concurrent_cycle_end();
+}
+
+static void print_ms_time_info(const char* prefix, const char* name,
+ NumberSeq& ns) {
+ log_trace(gc, marking)("%s%5d %12s: total time = %8.2f s (avg = %8.2f ms).",
+ prefix, ns.num(), name, ns.sum()/1000.0, ns.avg());
+ if (ns.num() > 0) {
+ log_trace(gc, marking)("%s [std. dev = %8.2f ms, max = %8.2f ms]",
+ prefix, ns.sd(), ns.maximum());
+ }
+}
+
+void G1ConcurrentMark::print_summary_info() {
+ LogHandle(gc, marking) log;
+ if (!log.is_trace()) {
+ return;
+ }
+
+ log.trace(" Concurrent marking:");
+ print_ms_time_info(" ", "init marks", _init_times);
+ print_ms_time_info(" ", "remarks", _remark_times);
+ {
+ print_ms_time_info(" ", "final marks", _remark_mark_times);
+ print_ms_time_info(" ", "weak refs", _remark_weak_ref_times);
+
+ }
+ print_ms_time_info(" ", "cleanups", _cleanup_times);
+ log.trace(" Final counting total time = %8.2f s (avg = %8.2f ms).",
+ _total_counting_time, (_cleanup_times.num() > 0 ? _total_counting_time * 1000.0 / (double)_cleanup_times.num() : 0.0));
+ if (G1ScrubRemSets) {
+ log.trace(" RS scrub total time = %8.2f s (avg = %8.2f ms).",
+ _total_rs_scrub_time, (_cleanup_times.num() > 0 ? _total_rs_scrub_time * 1000.0 / (double)_cleanup_times.num() : 0.0));
+ }
+ log.trace(" Total stop_world time = %8.2f s.",
+ (_init_times.sum() + _remark_times.sum() + _cleanup_times.sum())/1000.0);
+ log.trace(" Total concurrent time = %8.2f s (%8.2f s marking).",
+ cmThread()->vtime_accum(), cmThread()->vtime_mark_accum());
+}
+
+void G1ConcurrentMark::print_worker_threads_on(outputStream* st) const {
+ _parallel_workers->print_worker_threads_on(st);
+}
+
+void G1ConcurrentMark::print_on_error(outputStream* st) const {
+ st->print_cr("Marking Bits (Prev, Next): (CMBitMap*) " PTR_FORMAT ", (CMBitMap*) " PTR_FORMAT,
+ p2i(_prevMarkBitMap), p2i(_nextMarkBitMap));
+ _prevMarkBitMap->print_on_error(st, " Prev Bits: ");
+ _nextMarkBitMap->print_on_error(st, " Next Bits: ");
+}
+
+// We take a break if someone is trying to stop the world.
+bool G1ConcurrentMark::do_yield_check(uint worker_id) {
+ if (SuspendibleThreadSet::should_yield()) {
+ if (worker_id == 0) {
+ _g1h->g1_policy()->record_concurrent_pause();
+ }
+ SuspendibleThreadSet::yield();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+// Closure for iteration over bitmaps
+class G1CMBitMapClosure : public BitMapClosure {
+private:
+ // the bitmap that is being iterated over
+ G1CMBitMap* _nextMarkBitMap;
+ G1ConcurrentMark* _cm;
+ G1CMTask* _task;
+
+public:
+ G1CMBitMapClosure(G1CMTask *task, G1ConcurrentMark* cm, G1CMBitMap* nextMarkBitMap) :
+ _task(task), _cm(cm), _nextMarkBitMap(nextMarkBitMap) { }
+
+ bool do_bit(size_t offset) {
+ HeapWord* addr = _nextMarkBitMap->offsetToHeapWord(offset);
+ assert(_nextMarkBitMap->isMarked(addr), "invariant");
+ assert( addr < _cm->finger(), "invariant");
+ assert(addr >= _task->finger(), "invariant");
+
+ // We move that task's local finger along.
+ _task->move_finger_to(addr);
+
+ _task->scan_object(oop(addr));
+ // we only partially drain the local queue and global stack
+ _task->drain_local_queue(true);
+ _task->drain_global_stack(true);
+
+ // if the has_aborted flag has been raised, we need to bail out of
+ // the iteration
+ return !_task->has_aborted();
+ }
+};
+
+static ReferenceProcessor* get_cm_oop_closure_ref_processor(G1CollectedHeap* g1h) {
+ ReferenceProcessor* result = NULL;
+ if (G1UseConcMarkReferenceProcessing) {
+ result = g1h->ref_processor_cm();
+ assert(result != NULL, "should not be NULL");
+ }
+ return result;
+}
+
+G1CMOopClosure::G1CMOopClosure(G1CollectedHeap* g1h,
+ G1ConcurrentMark* cm,
+ G1CMTask* task)
+ : MetadataAwareOopClosure(get_cm_oop_closure_ref_processor(g1h)),
+ _g1h(g1h), _cm(cm), _task(task)
+{ }
+
+void G1CMTask::setup_for_region(HeapRegion* hr) {
+ assert(hr != NULL,
+ "claim_region() should have filtered out NULL regions");
+ _curr_region = hr;
+ _finger = hr->bottom();
+ update_region_limit();
+}
+
+void G1CMTask::update_region_limit() {
+ HeapRegion* hr = _curr_region;
+ HeapWord* bottom = hr->bottom();
+ HeapWord* limit = hr->next_top_at_mark_start();
+
+ if (limit == bottom) {
+ // The region was collected underneath our feet.
+ // We set the finger to bottom to ensure that the bitmap
+ // iteration that will follow this will not do anything.
+ // (this is not a condition that holds when we set the region up,
+ // as the region is not supposed to be empty in the first place)
+ _finger = bottom;
+ } else if (limit >= _region_limit) {
+ assert(limit >= _finger, "peace of mind");
+ } else {
+ assert(limit < _region_limit, "only way to get here");
+ // This can happen under some pretty unusual circumstances. An
+ // evacuation pause empties the region underneath our feet (NTAMS
+ // at bottom). We then do some allocation in the region (NTAMS
+ // stays at bottom), followed by the region being used as a GC
+ // alloc region (NTAMS will move to top() and the objects
+ // originally below it will be grayed). All objects now marked in
+ // the region are explicitly grayed, if below the global finger,
+ // and we do not need in fact to scan anything else. So, we simply
+ // set _finger to be limit to ensure that the bitmap iteration
+ // doesn't do anything.
+ _finger = limit;
+ }
+
+ _region_limit = limit;
+}
+
+void G1CMTask::giveup_current_region() {
+ assert(_curr_region != NULL, "invariant");
+ clear_region_fields();
+}
+
+void G1CMTask::clear_region_fields() {
+ // Values for these three fields that indicate that we're not
+ // holding on to a region.
+ _curr_region = NULL;
+ _finger = NULL;
+ _region_limit = NULL;
+}
+
+void G1CMTask::set_cm_oop_closure(G1CMOopClosure* cm_oop_closure) {
+ if (cm_oop_closure == NULL) {
+ assert(_cm_oop_closure != NULL, "invariant");
+ } else {
+ assert(_cm_oop_closure == NULL, "invariant");
+ }
+ _cm_oop_closure = cm_oop_closure;
+}
+
+void G1CMTask::reset(G1CMBitMap* nextMarkBitMap) {
+ guarantee(nextMarkBitMap != NULL, "invariant");
+ _nextMarkBitMap = nextMarkBitMap;
+ clear_region_fields();
+
+ _calls = 0;
+ _elapsed_time_ms = 0.0;
+ _termination_time_ms = 0.0;
+ _termination_start_time_ms = 0.0;
+}
+
+bool G1CMTask::should_exit_termination() {
+ regular_clock_call();
+ // This is called when we are in the termination protocol. We should
+ // quit if, for some reason, this task wants to abort or the global
+ // stack is not empty (this means that we can get work from it).
+ return !_cm->mark_stack_empty() || has_aborted();
+}
+
+void G1CMTask::reached_limit() {
+ assert(_words_scanned >= _words_scanned_limit ||
+ _refs_reached >= _refs_reached_limit ,
+ "shouldn't have been called otherwise");
+ regular_clock_call();
+}
+
+void G1CMTask::regular_clock_call() {
+ if (has_aborted()) return;
+
+ // First, we need to recalculate the words scanned and refs reached
+ // limits for the next clock call.
+ recalculate_limits();
+
+ // During the regular clock call we do the following
+
+ // (1) If an overflow has been flagged, then we abort.
+ if (_cm->has_overflown()) {
+ set_has_aborted();
+ return;
+ }
+
+ // If we are not concurrent (i.e. we're doing remark) we don't need
+ // to check anything else. The other steps are only needed during
+ // the concurrent marking phase.
+ if (!concurrent()) return;
+
+ // (2) If marking has been aborted for Full GC, then we also abort.
+ if (_cm->has_aborted()) {
+ set_has_aborted();
+ return;
+ }
+
+ double curr_time_ms = os::elapsedVTime() * 1000.0;
+
+ // (4) We check whether we should yield. If we have to, then we abort.
+ if (SuspendibleThreadSet::should_yield()) {
+ // We should yield. To do this we abort the task. The caller is
+ // responsible for yielding.
+ set_has_aborted();
+ return;
+ }
+
+ // (5) We check whether we've reached our time quota. If we have,
+ // then we abort.
+ double elapsed_time_ms = curr_time_ms - _start_time_ms;
+ if (elapsed_time_ms > _time_target_ms) {
+ set_has_aborted();
+ _has_timed_out = true;
+ return;
+ }
+
+ // (6) Finally, we check whether there are enough completed STAB
+ // buffers available for processing. If there are, we abort.
+ SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
+ if (!_draining_satb_buffers && satb_mq_set.process_completed_buffers()) {
+ // we do need to process SATB buffers, we'll abort and restart
+ // the marking task to do so
+ set_has_aborted();
+ return;
+ }
+}
+
+void G1CMTask::recalculate_limits() {
+ _real_words_scanned_limit = _words_scanned + words_scanned_period;
+ _words_scanned_limit = _real_words_scanned_limit;
+
+ _real_refs_reached_limit = _refs_reached + refs_reached_period;
+ _refs_reached_limit = _real_refs_reached_limit;
+}
+
+void G1CMTask::decrease_limits() {
+ // This is called when we believe that we're going to do an infrequent
+ // operation which will increase the per byte scanned cost (i.e. move
+ // entries to/from the global stack). It basically tries to decrease the
+ // scanning limit so that the clock is called earlier.
+
+ _words_scanned_limit = _real_words_scanned_limit -
+ 3 * words_scanned_period / 4;
+ _refs_reached_limit = _real_refs_reached_limit -
+ 3 * refs_reached_period / 4;
+}
+
+void G1CMTask::move_entries_to_global_stack() {
+ // local array where we'll store the entries that will be popped
+ // from the local queue
+ oop buffer[global_stack_transfer_size];
+
+ int n = 0;
+ oop obj;
+ while (n < global_stack_transfer_size && _task_queue->pop_local(obj)) {
+ buffer[n] = obj;
+ ++n;
+ }
+
+ if (n > 0) {
+ // we popped at least one entry from the local queue
+
+ if (!_cm->mark_stack_push(buffer, n)) {
+ set_has_aborted();
+ }
+ }
+
+ // this operation was quite expensive, so decrease the limits
+ decrease_limits();
+}
+
+void G1CMTask::get_entries_from_global_stack() {
+ // local array where we'll store the entries that will be popped
+ // from the global stack.
+ oop buffer[global_stack_transfer_size];
+ int n;
+ _cm->mark_stack_pop(buffer, global_stack_transfer_size, &n);
+ assert(n <= global_stack_transfer_size,
+ "we should not pop more than the given limit");
+ if (n > 0) {
+ // yes, we did actually pop at least one entry
+ for (int i = 0; i < n; ++i) {
+ bool success = _task_queue->push(buffer[i]);
+ // We only call this when the local queue is empty or under a
+ // given target limit. So, we do not expect this push to fail.
+ assert(success, "invariant");
+ }
+ }
+
+ // this operation was quite expensive, so decrease the limits
+ decrease_limits();
+}
+
+void G1CMTask::drain_local_queue(bool partially) {
+ if (has_aborted()) return;
+
+ // Decide what the target size is, depending whether we're going to
+ // drain it partially (so that other tasks can steal if they run out
+ // of things to do) or totally (at the very end).
+ size_t target_size;
+ if (partially) {
+ target_size = MIN2((size_t)_task_queue->max_elems()/3, GCDrainStackTargetSize);
+ } else {
+ target_size = 0;
+ }
+
+ if (_task_queue->size() > target_size) {
+ oop obj;
+ bool ret = _task_queue->pop_local(obj);
+ while (ret) {
+ assert(_g1h->is_in_g1_reserved((HeapWord*) obj), "invariant" );
+ assert(!_g1h->is_on_master_free_list(
+ _g1h->heap_region_containing((HeapWord*) obj)), "invariant");
+
+ scan_object(obj);
+
+ if (_task_queue->size() <= target_size || has_aborted()) {
+ ret = false;
+ } else {
+ ret = _task_queue->pop_local(obj);
+ }
+ }
+ }
+}
+
+void G1CMTask::drain_global_stack(bool partially) {
+ if (has_aborted()) return;
+
+ // We have a policy to drain the local queue before we attempt to
+ // drain the global stack.
+ assert(partially || _task_queue->size() == 0, "invariant");
+
+ // Decide what the target size is, depending whether we're going to
+ // drain it partially (so that other tasks can steal if they run out
+ // of things to do) or totally (at the very end). Notice that,
+ // because we move entries from the global stack in chunks or
+ // because another task might be doing the same, we might in fact
+ // drop below the target. But, this is not a problem.
+ size_t target_size;
+ if (partially) {
+ target_size = _cm->partial_mark_stack_size_target();
+ } else {
+ target_size = 0;
+ }
+
+ if (_cm->mark_stack_size() > target_size) {
+ while (!has_aborted() && _cm->mark_stack_size() > target_size) {
+ get_entries_from_global_stack();
+ drain_local_queue(partially);
+ }
+ }
+}
+
+// SATB Queue has several assumptions on whether to call the par or
+// non-par versions of the methods. this is why some of the code is
+// replicated. We should really get rid of the single-threaded version
+// of the code to simplify things.
+void G1CMTask::drain_satb_buffers() {
+ if (has_aborted()) return;
+
+ // We set this so that the regular clock knows that we're in the
+ // middle of draining buffers and doesn't set the abort flag when it
+ // notices that SATB buffers are available for draining. It'd be
+ // very counter productive if it did that. :-)
+ _draining_satb_buffers = true;
+
+ G1CMSATBBufferClosure satb_cl(this, _g1h);
+ SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
+
+ // This keeps claiming and applying the closure to completed buffers
+ // until we run out of buffers or we need to abort.
+ while (!has_aborted() &&
+ satb_mq_set.apply_closure_to_completed_buffer(&satb_cl)) {
+ regular_clock_call();
+ }
+
+ _draining_satb_buffers = false;
+
+ assert(has_aborted() ||
+ concurrent() ||
+ satb_mq_set.completed_buffers_num() == 0, "invariant");
+
+ // again, this was a potentially expensive operation, decrease the
+ // limits to get the regular clock call early
+ decrease_limits();
+}
+
+void G1CMTask::print_stats() {
+ log_debug(gc, stats)("Marking Stats, task = %u, calls = %d",
+ _worker_id, _calls);
+ log_debug(gc, stats)(" Elapsed time = %1.2lfms, Termination time = %1.2lfms",
+ _elapsed_time_ms, _termination_time_ms);
+ log_debug(gc, stats)(" Step Times (cum): num = %d, avg = %1.2lfms, sd = %1.2lfms",
+ _step_times_ms.num(), _step_times_ms.avg(),
+ _step_times_ms.sd());
+ log_debug(gc, stats)(" max = %1.2lfms, total = %1.2lfms",
+ _step_times_ms.maximum(), _step_times_ms.sum());
+}
+
+bool G1ConcurrentMark::try_stealing(uint worker_id, int* hash_seed, oop& obj) {
+ return _task_queues->steal(worker_id, hash_seed, obj);
+}
+
+/*****************************************************************************
+
+ The do_marking_step(time_target_ms, ...) method is the building
+ block of the parallel marking framework. It can be called in parallel
+ with other invocations of do_marking_step() on different tasks
+ (but only one per task, obviously) and concurrently with the
+ mutator threads, or during remark, hence it eliminates the need
+ for two versions of the code. When called during remark, it will
+ pick up from where the task left off during the concurrent marking
+ phase. Interestingly, tasks are also claimable during evacuation
+ pauses too, since do_marking_step() ensures that it aborts before
+ it needs to yield.
+
+ The data structures that it uses to do marking work are the
+ following:
+
+ (1) Marking Bitmap. If there are gray objects that appear only
+ on the bitmap (this happens either when dealing with an overflow
+ or when the initial marking phase has simply marked the roots
+ and didn't push them on the stack), then tasks claim heap
+ regions whose bitmap they then scan to find gray objects. A
+ global finger indicates where the end of the last claimed region
+ is. A local finger indicates how far into the region a task has
+ scanned. The two fingers are used to determine how to gray an
+ object (i.e. whether simply marking it is OK, as it will be
+ visited by a task in the future, or whether it needs to be also
+ pushed on a stack).
+
+ (2) Local Queue. The local queue of the task which is accessed
+ reasonably efficiently by the task. Other tasks can steal from
+ it when they run out of work. Throughout the marking phase, a
+ task attempts to keep its local queue short but not totally
+ empty, so that entries are available for stealing by other
+ tasks. Only when there is no more work, a task will totally
+ drain its local queue.
+
+ (3) Global Mark Stack. This handles local queue overflow. During
+ marking only sets of entries are moved between it and the local
+ queues, as access to it requires a mutex and more fine-grain
+ interaction with it which might cause contention. If it
+ overflows, then the marking phase should restart and iterate
+ over the bitmap to identify gray objects. Throughout the marking
+ phase, tasks attempt to keep the global mark stack at a small
+ length but not totally empty, so that entries are available for
+ popping by other tasks. Only when there is no more work, tasks
+ will totally drain the global mark stack.
+
+ (4) SATB Buffer Queue. This is where completed SATB buffers are
+ made available. Buffers are regularly removed from this queue
+ and scanned for roots, so that the queue doesn't get too
+ long. During remark, all completed buffers are processed, as
+ well as the filled in parts of any uncompleted buffers.
+
+ The do_marking_step() method tries to abort when the time target
+ has been reached. There are a few other cases when the
+ do_marking_step() method also aborts:
+
+ (1) When the marking phase has been aborted (after a Full GC).
+
+ (2) When a global overflow (on the global stack) has been
+ triggered. Before the task aborts, it will actually sync up with
+ the other tasks to ensure that all the marking data structures
+ (local queues, stacks, fingers etc.) are re-initialized so that
+ when do_marking_step() completes, the marking phase can
+ immediately restart.
+
+ (3) When enough completed SATB buffers are available. The
+ do_marking_step() method only tries to drain SATB buffers right
+ at the beginning. So, if enough buffers are available, the
+ marking step aborts and the SATB buffers are processed at
+ the beginning of the next invocation.
+
+ (4) To yield. when we have to yield then we abort and yield
+ right at the end of do_marking_step(). This saves us from a lot
+ of hassle as, by yielding we might allow a Full GC. If this
+ happens then objects will be compacted underneath our feet, the
+ heap might shrink, etc. We save checking for this by just
+ aborting and doing the yield right at the end.
+
+ From the above it follows that the do_marking_step() method should
+ be called in a loop (or, otherwise, regularly) until it completes.
+
+ If a marking step completes without its has_aborted() flag being
+ true, it means it has completed the current marking phase (and
+ also all other marking tasks have done so and have all synced up).
+
+ A method called regular_clock_call() is invoked "regularly" (in
+ sub ms intervals) throughout marking. It is this clock method that
+ checks all the abort conditions which were mentioned above and
+ decides when the task should abort. A work-based scheme is used to
+ trigger this clock method: when the number of object words the
+ marking phase has scanned or the number of references the marking
+ phase has visited reach a given limit. Additional invocations to
+ the method clock have been planted in a few other strategic places
+ too. The initial reason for the clock method was to avoid calling
+ vtime too regularly, as it is quite expensive. So, once it was in
+ place, it was natural to piggy-back all the other conditions on it
+ too and not constantly check them throughout the code.
+
+ If do_termination is true then do_marking_step will enter its
+ termination protocol.
+
+ The value of is_serial must be true when do_marking_step is being
+ called serially (i.e. by the VMThread) and do_marking_step should
+ skip any synchronization in the termination and overflow code.
+ Examples include the serial remark code and the serial reference
+ processing closures.
+
+ The value of is_serial must be false when do_marking_step is
+ being called by any of the worker threads in a work gang.
+ Examples include the concurrent marking code (CMMarkingTask),
+ the MT remark code, and the MT reference processing closures.
+
+ *****************************************************************************/
+
+void G1CMTask::do_marking_step(double time_target_ms,
+ bool do_termination,
+ bool is_serial) {
+ assert(time_target_ms >= 1.0, "minimum granularity is 1ms");
+ assert(concurrent() == _cm->concurrent(), "they should be the same");
+
+ G1CollectorPolicy* g1_policy = _g1h->g1_policy();
+ assert(_task_queues != NULL, "invariant");
+ assert(_task_queue != NULL, "invariant");
+ assert(_task_queues->queue(_worker_id) == _task_queue, "invariant");
+
+ assert(!_claimed,
+ "only one thread should claim this task at any one time");
+
+ // OK, this doesn't safeguard again all possible scenarios, as it is
+ // possible for two threads to set the _claimed flag at the same
+ // time. But it is only for debugging purposes anyway and it will
+ // catch most problems.
+ _claimed = true;
+
+ _start_time_ms = os::elapsedVTime() * 1000.0;
+
+ // If do_stealing is true then do_marking_step will attempt to
+ // steal work from the other G1CMTasks. It only makes sense to
+ // enable stealing when the termination protocol is enabled
+ // and do_marking_step() is not being called serially.
+ bool do_stealing = do_termination && !is_serial;
+
+ double diff_prediction_ms = _g1h->g1_policy()->predictor().get_new_prediction(&_marking_step_diffs_ms);
+ _time_target_ms = time_target_ms - diff_prediction_ms;
+
+ // set up the variables that are used in the work-based scheme to
+ // call the regular clock method
+ _words_scanned = 0;
+ _refs_reached = 0;
+ recalculate_limits();
+
+ // clear all flags
+ clear_has_aborted();
+ _has_timed_out = false;
+ _draining_satb_buffers = false;
+
+ ++_calls;
+
+ // Set up the bitmap and oop closures. Anything that uses them is
+ // eventually called from this method, so it is OK to allocate these
+ // statically.
+ G1CMBitMapClosure bitmap_closure(this, _cm, _nextMarkBitMap);
+ G1CMOopClosure cm_oop_closure(_g1h, _cm, this);
+ set_cm_oop_closure(&cm_oop_closure);
+
+ if (_cm->has_overflown()) {
+ // This can happen if the mark stack overflows during a GC pause
+ // and this task, after a yield point, restarts. We have to abort
+ // as we need to get into the overflow protocol which happens
+ // right at the end of this task.
+ set_has_aborted();
+ }
+
+ // First drain any available SATB buffers. After this, we will not
+ // look at SATB buffers before the next invocation of this method.
+ // If enough completed SATB buffers are queued up, the regular clock
+ // will abort this task so that it restarts.
+ drain_satb_buffers();
+ // ...then partially drain the local queue and the global stack
+ drain_local_queue(true);
+ drain_global_stack(true);
+
+ do {
+ if (!has_aborted() && _curr_region != NULL) {
+ // This means that we're already holding on to a region.
+ assert(_finger != NULL, "if region is not NULL, then the finger "
+ "should not be NULL either");
+
+ // We might have restarted this task after an evacuation pause
+ // which might have evacuated the region we're holding on to
+ // underneath our feet. Let's read its limit again to make sure
+ // that we do not iterate over a region of the heap that
+ // contains garbage (update_region_limit() will also move
+ // _finger to the start of the region if it is found empty).
+ update_region_limit();
+ // We will start from _finger not from the start of the region,
+ // as we might be restarting this task after aborting half-way
+ // through scanning this region. In this case, _finger points to
+ // the address where we last found a marked object. If this is a
+ // fresh region, _finger points to start().
+ MemRegion mr = MemRegion(_finger, _region_limit);
+
+ assert(!_curr_region->is_humongous() || mr.start() == _curr_region->bottom(),
+ "humongous regions should go around loop once only");
+
+ // Some special cases:
+ // If the memory region is empty, we can just give up the region.
+ // If the current region is humongous then we only need to check
+ // the bitmap for the bit associated with the start of the object,
+ // scan the object if it's live, and give up the region.
+ // Otherwise, let's iterate over the bitmap of the part of the region
+ // that is left.
+ // If the iteration is successful, give up the region.
+ if (mr.is_empty()) {
+ giveup_current_region();
+ regular_clock_call();
+ } else if (_curr_region->is_humongous() && mr.start() == _curr_region->bottom()) {
+ if (_nextMarkBitMap->isMarked(mr.start())) {
+ // The object is marked - apply the closure
+ BitMap::idx_t offset = _nextMarkBitMap->heapWordToOffset(mr.start());
+ bitmap_closure.do_bit(offset);
+ }
+ // Even if this task aborted while scanning the humongous object
+ // we can (and should) give up the current region.
+ giveup_current_region();
+ regular_clock_call();
+ } else if (_nextMarkBitMap->iterate(&bitmap_closure, mr)) {
+ giveup_current_region();
+ regular_clock_call();
+ } else {
+ assert(has_aborted(), "currently the only way to do so");
+ // The only way to abort the bitmap iteration is to return
+ // false from the do_bit() method. However, inside the
+ // do_bit() method we move the _finger to point to the
+ // object currently being looked at. So, if we bail out, we
+ // have definitely set _finger to something non-null.
+ assert(_finger != NULL, "invariant");
+
+ // Region iteration was actually aborted. So now _finger
+ // points to the address of the object we last scanned. If we
+ // leave it there, when we restart this task, we will rescan
+ // the object. It is easy to avoid this. We move the finger by
+ // enough to point to the next possible object header (the
+ // bitmap knows by how much we need to move it as it knows its
+ // granularity).
+ assert(_finger < _region_limit, "invariant");
+ HeapWord* new_finger = _nextMarkBitMap->nextObject(_finger);
+ // Check if bitmap iteration was aborted while scanning the last object
+ if (new_finger >= _region_limit) {
+ giveup_current_region();
+ } else {
+ move_finger_to(new_finger);
+ }
+ }
+ }
+ // At this point we have either completed iterating over the
+ // region we were holding on to, or we have aborted.
+
+ // We then partially drain the local queue and the global stack.
+ // (Do we really need this?)
+ drain_local_queue(true);
+ drain_global_stack(true);
+
+ // Read the note on the claim_region() method on why it might
+ // return NULL with potentially more regions available for
+ // claiming and why we have to check out_of_regions() to determine
+ // whether we're done or not.
+ while (!has_aborted() && _curr_region == NULL && !_cm->out_of_regions()) {
+ // We are going to try to claim a new region. We should have
+ // given up on the previous one.
+ // Separated the asserts so that we know which one fires.
+ assert(_curr_region == NULL, "invariant");
+ assert(_finger == NULL, "invariant");
+ assert(_region_limit == NULL, "invariant");
+ HeapRegion* claimed_region = _cm->claim_region(_worker_id);
+ if (claimed_region != NULL) {
+ // Yes, we managed to claim one
+ setup_for_region(claimed_region);
+ assert(_curr_region == claimed_region, "invariant");
+ }
+ // It is important to call the regular clock here. It might take
+ // a while to claim a region if, for example, we hit a large
+ // block of empty regions. So we need to call the regular clock
+ // method once round the loop to make sure it's called
+ // frequently enough.
+ regular_clock_call();
+ }
+
+ if (!has_aborted() && _curr_region == NULL) {
+ assert(_cm->out_of_regions(),
+ "at this point we should be out of regions");
+ }
+ } while ( _curr_region != NULL && !has_aborted());
+
+ if (!has_aborted()) {
+ // We cannot check whether the global stack is empty, since other
+ // tasks might be pushing objects to it concurrently.
+ assert(_cm->out_of_regions(),
+ "at this point we should be out of regions");
+ // Try to reduce the number of available SATB buffers so that
+ // remark has less work to do.
+ drain_satb_buffers();
+ }
+
+ // Since we've done everything else, we can now totally drain the
+ // local queue and global stack.
+ drain_local_queue(false);
+ drain_global_stack(false);
+
+ // Attempt at work stealing from other task's queues.
+ if (do_stealing && !has_aborted()) {
+ // We have not aborted. This means that we have finished all that
+ // we could. Let's try to do some stealing...
+
+ // We cannot check whether the global stack is empty, since other
+ // tasks might be pushing objects to it concurrently.
+ assert(_cm->out_of_regions() && _task_queue->size() == 0,
+ "only way to reach here");
+ while (!has_aborted()) {
+ oop obj;
+ if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) {
+ assert(_nextMarkBitMap->isMarked((HeapWord*) obj),
+ "any stolen object should be marked");
+ scan_object(obj);
+
+ // And since we're towards the end, let's totally drain the
+ // local queue and global stack.
+ drain_local_queue(false);
+ drain_global_stack(false);
+ } else {
+ break;
+ }
+ }
+ }
+
+ // We still haven't aborted. Now, let's try to get into the
+ // termination protocol.
+ if (do_termination && !has_aborted()) {
+ // We cannot check whether the global stack is empty, since other
+ // tasks might be concurrently pushing objects on it.
+ // Separated the asserts so that we know which one fires.
+ assert(_cm->out_of_regions(), "only way to reach here");
+ assert(_task_queue->size() == 0, "only way to reach here");
+ _termination_start_time_ms = os::elapsedVTime() * 1000.0;
+
+ // The G1CMTask class also extends the TerminatorTerminator class,
+ // hence its should_exit_termination() method will also decide
+ // whether to exit the termination protocol or not.
+ bool finished = (is_serial ||
+ _cm->terminator()->offer_termination(this));
+ double termination_end_time_ms = os::elapsedVTime() * 1000.0;
+ _termination_time_ms +=
+ termination_end_time_ms - _termination_start_time_ms;
+
+ if (finished) {
+ // We're all done.
+
+ if (_worker_id == 0) {
+ // let's allow task 0 to do this
+ if (concurrent()) {
+ assert(_cm->concurrent_marking_in_progress(), "invariant");
+ // we need to set this to false before the next
+ // safepoint. This way we ensure that the marking phase
+ // doesn't observe any more heap expansions.
+ _cm->clear_concurrent_marking_in_progress();
+ }
+ }
+
+ // We can now guarantee that the global stack is empty, since
+ // all other tasks have finished. We separated the guarantees so
+ // that, if a condition is false, we can immediately find out
+ // which one.
+ guarantee(_cm->out_of_regions(), "only way to reach here");
+ guarantee(_cm->mark_stack_empty(), "only way to reach here");
+ guarantee(_task_queue->size() == 0, "only way to reach here");
+ guarantee(!_cm->has_overflown(), "only way to reach here");
+ guarantee(!_cm->mark_stack_overflow(), "only way to reach here");
+ } else {
+ // Apparently there's more work to do. Let's abort this task. It
+ // will restart it and we can hopefully find more things to do.
+ set_has_aborted();
+ }
+ }
+
+ // Mainly for debugging purposes to make sure that a pointer to the
+ // closure which was statically allocated in this frame doesn't
+ // escape it by accident.
+ set_cm_oop_closure(NULL);
+ double end_time_ms = os::elapsedVTime() * 1000.0;
+ double elapsed_time_ms = end_time_ms - _start_time_ms;
+ // Update the step history.
+ _step_times_ms.add(elapsed_time_ms);
+
+ if (has_aborted()) {
+ // The task was aborted for some reason.
+ if (_has_timed_out) {
+ double diff_ms = elapsed_time_ms - _time_target_ms;
+ // Keep statistics of how well we did with respect to hitting
+ // our target only if we actually timed out (if we aborted for
+ // other reasons, then the results might get skewed).
+ _marking_step_diffs_ms.add(diff_ms);
+ }
+
+ if (_cm->has_overflown()) {
+ // This is the interesting one. We aborted because a global
+ // overflow was raised. This means we have to restart the
+ // marking phase and start iterating over regions. However, in
+ // order to do this we have to make sure that all tasks stop
+ // what they are doing and re-initialize in a safe manner. We
+ // will achieve this with the use of two barrier sync points.
+
+ if (!is_serial) {
+ // We only need to enter the sync barrier if being called
+ // from a parallel context
+ _cm->enter_first_sync_barrier(_worker_id);
+
+ // When we exit this sync barrier we know that all tasks have
+ // stopped doing marking work. So, it's now safe to
+ // re-initialize our data structures. At the end of this method,
+ // task 0 will clear the global data structures.
+ }
+
+ // We clear the local state of this task...
+ clear_region_fields();
+
+ if (!is_serial) {
+ // ...and enter the second barrier.
+ _cm->enter_second_sync_barrier(_worker_id);
+ }
+ // At this point, if we're during the concurrent phase of
+ // marking, everything has been re-initialized and we're
+ // ready to restart.
+ }
+ }
+
+ _claimed = false;
+}
+
+G1CMTask::G1CMTask(uint worker_id,
+ G1ConcurrentMark* cm,
+ size_t* marked_bytes,
+ BitMap* card_bm,
+ G1CMTaskQueue* task_queue,
+ G1CMTaskQueueSet* task_queues)
+ : _g1h(G1CollectedHeap::heap()),
+ _worker_id(worker_id), _cm(cm),
+ _claimed(false),
+ _nextMarkBitMap(NULL), _hash_seed(17),
+ _task_queue(task_queue),
+ _task_queues(task_queues),
+ _cm_oop_closure(NULL),
+ _marked_bytes_array(marked_bytes),
+ _card_bm(card_bm) {
+ guarantee(task_queue != NULL, "invariant");
+ guarantee(task_queues != NULL, "invariant");
+
+ _marking_step_diffs_ms.add(0.5);
+}
+
+// These are formatting macros that are used below to ensure
+// consistent formatting. The *_H_* versions are used to format the
+// header for a particular value and they should be kept consistent
+// with the corresponding macro. Also note that most of the macros add
+// the necessary white space (as a prefix) which makes them a bit
+// easier to compose.
+
+// All the output lines are prefixed with this string to be able to
+// identify them easily in a large log file.
+#define G1PPRL_LINE_PREFIX "###"
+
+#define G1PPRL_ADDR_BASE_FORMAT " " PTR_FORMAT "-" PTR_FORMAT
+#ifdef _LP64
+#define G1PPRL_ADDR_BASE_H_FORMAT " %37s"
+#else // _LP64
+#define G1PPRL_ADDR_BASE_H_FORMAT " %21s"
+#endif // _LP64
+
+// For per-region info
+#define G1PPRL_TYPE_FORMAT " %-4s"
+#define G1PPRL_TYPE_H_FORMAT " %4s"
+#define G1PPRL_BYTE_FORMAT " " SIZE_FORMAT_W(9)
+#define G1PPRL_BYTE_H_FORMAT " %9s"
+#define G1PPRL_DOUBLE_FORMAT " %14.1f"
+#define G1PPRL_DOUBLE_H_FORMAT " %14s"
+
+// For summary info
+#define G1PPRL_SUM_ADDR_FORMAT(tag) " " tag ":" G1PPRL_ADDR_BASE_FORMAT
+#define G1PPRL_SUM_BYTE_FORMAT(tag) " " tag ": " SIZE_FORMAT
+#define G1PPRL_SUM_MB_FORMAT(tag) " " tag ": %1.2f MB"
+#define G1PPRL_SUM_MB_PERC_FORMAT(tag) G1PPRL_SUM_MB_FORMAT(tag) " / %1.2f %%"
+
+G1PrintRegionLivenessInfoClosure::
+G1PrintRegionLivenessInfoClosure(const char* phase_name)
+ : _total_used_bytes(0), _total_capacity_bytes(0),
+ _total_prev_live_bytes(0), _total_next_live_bytes(0),
+ _hum_used_bytes(0), _hum_capacity_bytes(0),
+ _hum_prev_live_bytes(0), _hum_next_live_bytes(0),
+ _total_remset_bytes(0), _total_strong_code_roots_bytes(0) {
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+ MemRegion g1_reserved = g1h->g1_reserved();
+ double now = os::elapsedTime();
+
+ // Print the header of the output.
+ log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" PHASE %s @ %1.3f", phase_name, now);
+ log_trace(gc, liveness)(G1PPRL_LINE_PREFIX" HEAP"
+ G1PPRL_SUM_ADDR_FORMAT("reserved")
+ G1PPRL_SUM_BYTE_FORMAT("region-size"),
+ p2i(g1_reserved.start()), p2i(g1_reserved.end()),
+ HeapRegion::GrainBytes);
+ log_trace(gc, liveness)(G1PPRL_LINE_PREFIX);
+ log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
+ G1PPRL_TYPE_H_FORMAT
+ G1PPRL_ADDR_BASE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_DOUBLE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT,
+ "type", "address-range",
+ "used", "prev-live", "next-live", "gc-eff",
+ "remset", "code-roots");
+ log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
+ G1PPRL_TYPE_H_FORMAT
+ G1PPRL_ADDR_BASE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_DOUBLE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT
+ G1PPRL_BYTE_H_FORMAT,
+ "", "",
+ "(bytes)", "(bytes)", "(bytes)", "(bytes/ms)",
+ "(bytes)", "(bytes)");
+}
+
+// It takes as a parameter a reference to one of the _hum_* fields, it
+// deduces the corresponding value for a region in a humongous region
+// series (either the region size, or what's left if the _hum_* field
+// is < the region size), and updates the _hum_* field accordingly.
+size_t G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* hum_bytes) {
+ size_t bytes = 0;
+ // The > 0 check is to deal with the prev and next live bytes which
+ // could be 0.
+ if (*hum_bytes > 0) {
+ bytes = MIN2(HeapRegion::GrainBytes, *hum_bytes);
+ *hum_bytes -= bytes;
+ }
+ return bytes;
+}
+
+// It deduces the values for a region in a humongous region series
+// from the _hum_* fields and updates those accordingly. It assumes
+// that that _hum_* fields have already been set up from the "starts
+// humongous" region and we visit the regions in address order.
+void G1PrintRegionLivenessInfoClosure::get_hum_bytes(size_t* used_bytes,
+ size_t* capacity_bytes,
+ size_t* prev_live_bytes,
+ size_t* next_live_bytes) {
+ assert(_hum_used_bytes > 0 && _hum_capacity_bytes > 0, "pre-condition");
+ *used_bytes = get_hum_bytes(&_hum_used_bytes);
+ *capacity_bytes = get_hum_bytes(&_hum_capacity_bytes);
+ *prev_live_bytes = get_hum_bytes(&_hum_prev_live_bytes);
+ *next_live_bytes = get_hum_bytes(&_hum_next_live_bytes);
+}
+
+bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) {
+ const char* type = r->get_type_str();
+ HeapWord* bottom = r->bottom();
+ HeapWord* end = r->end();
+ size_t capacity_bytes = r->capacity();
+ size_t used_bytes = r->used();
+ size_t prev_live_bytes = r->live_bytes();
+ size_t next_live_bytes = r->next_live_bytes();
+ double gc_eff = r->gc_efficiency();
+ size_t remset_bytes = r->rem_set()->mem_size();
+ size_t strong_code_roots_bytes = r->rem_set()->strong_code_roots_mem_size();
+
+ if (r->is_starts_humongous()) {
+ assert(_hum_used_bytes == 0 && _hum_capacity_bytes == 0 &&
+ _hum_prev_live_bytes == 0 && _hum_next_live_bytes == 0,
+ "they should have been zeroed after the last time we used them");
+ // Set up the _hum_* fields.
+ _hum_capacity_bytes = capacity_bytes;
+ _hum_used_bytes = used_bytes;
+ _hum_prev_live_bytes = prev_live_bytes;
+ _hum_next_live_bytes = next_live_bytes;
+ get_hum_bytes(&used_bytes, &capacity_bytes,
+ &prev_live_bytes, &next_live_bytes);
+ end = bottom + HeapRegion::GrainWords;
+ } else if (r->is_continues_humongous()) {
+ get_hum_bytes(&used_bytes, &capacity_bytes,
+ &prev_live_bytes, &next_live_bytes);
+ assert(end == bottom + HeapRegion::GrainWords, "invariant");
+ }
+
+ _total_used_bytes += used_bytes;
+ _total_capacity_bytes += capacity_bytes;
+ _total_prev_live_bytes += prev_live_bytes;
+ _total_next_live_bytes += next_live_bytes;
+ _total_remset_bytes += remset_bytes;
+ _total_strong_code_roots_bytes += strong_code_roots_bytes;
+
+ // Print a line for this particular region.
+ log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
+ G1PPRL_TYPE_FORMAT
+ G1PPRL_ADDR_BASE_FORMAT
+ G1PPRL_BYTE_FORMAT
+ G1PPRL_BYTE_FORMAT
+ G1PPRL_BYTE_FORMAT
+ G1PPRL_DOUBLE_FORMAT
+ G1PPRL_BYTE_FORMAT
+ G1PPRL_BYTE_FORMAT,
+ type, p2i(bottom), p2i(end),
+ used_bytes, prev_live_bytes, next_live_bytes, gc_eff,
+ remset_bytes, strong_code_roots_bytes);
+
+ return false;
+}
+
+G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() {
+ // add static memory usages to remembered set sizes
+ _total_remset_bytes += HeapRegionRemSet::fl_mem_size() + HeapRegionRemSet::static_mem_size();
+ // Print the footer of the output.
+ log_trace(gc, liveness)(G1PPRL_LINE_PREFIX);
+ log_trace(gc, liveness)(G1PPRL_LINE_PREFIX
+ " SUMMARY"
+ G1PPRL_SUM_MB_FORMAT("capacity")
+ G1PPRL_SUM_MB_PERC_FORMAT("used")
+ G1PPRL_SUM_MB_PERC_FORMAT("prev-live")
+ G1PPRL_SUM_MB_PERC_FORMAT("next-live")
+ G1PPRL_SUM_MB_FORMAT("remset")
+ G1PPRL_SUM_MB_FORMAT("code-roots"),
+ bytes_to_mb(_total_capacity_bytes),
+ bytes_to_mb(_total_used_bytes),
+ perc(_total_used_bytes, _total_capacity_bytes),
+ bytes_to_mb(_total_prev_live_bytes),
+ perc(_total_prev_live_bytes, _total_capacity_bytes),
+ bytes_to_mb(_total_next_live_bytes),
+ perc(_total_next_live_bytes, _total_capacity_bytes),
+ bytes_to_mb(_total_remset_bytes),
+ bytes_to_mb(_total_strong_code_roots_bytes));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,1024 @@
+/*
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1CONCURRENTMARK_HPP
+#define SHARE_VM_GC_G1_G1CONCURRENTMARK_HPP
+
+#include "classfile/javaClasses.hpp"
+#include "gc/g1/g1RegionToSpaceMapper.hpp"
+#include "gc/g1/heapRegionSet.hpp"
+#include "gc/shared/taskqueue.hpp"
+
+class G1CollectedHeap;
+class G1CMBitMap;
+class G1CMTask;
+class G1ConcurrentMark;
+typedef GenericTaskQueue<oop, mtGC> G1CMTaskQueue;
+typedef GenericTaskQueueSet<G1CMTaskQueue, mtGC> G1CMTaskQueueSet;
+
+// Closure used by CM during concurrent reference discovery
+// and reference processing (during remarking) to determine
+// if a particular object is alive. It is primarily used
+// to determine if referents of discovered reference objects
+// are alive. An instance is also embedded into the
+// reference processor as the _is_alive_non_header field
+class G1CMIsAliveClosure: public BoolObjectClosure {
+ G1CollectedHeap* _g1;
+ public:
+ G1CMIsAliveClosure(G1CollectedHeap* g1) : _g1(g1) { }
+
+ bool do_object_b(oop obj);
+};
+
+// A generic CM bit map. This is essentially a wrapper around the BitMap
+// class, with one bit per (1<<_shifter) HeapWords.
+
+class G1CMBitMapRO VALUE_OBJ_CLASS_SPEC {
+ protected:
+ HeapWord* _bmStartWord; // base address of range covered by map
+ size_t _bmWordSize; // map size (in #HeapWords covered)
+ const int _shifter; // map to char or bit
+ BitMap _bm; // the bit map itself
+
+ public:
+ // constructor
+ G1CMBitMapRO(int shifter);
+
+ // inquiries
+ HeapWord* startWord() const { return _bmStartWord; }
+ // the following is one past the last word in space
+ HeapWord* endWord() const { return _bmStartWord + _bmWordSize; }
+
+ // read marks
+
+ bool isMarked(HeapWord* addr) const {
+ assert(_bmStartWord <= addr && addr < (_bmStartWord + _bmWordSize),
+ "outside underlying space?");
+ return _bm.at(heapWordToOffset(addr));
+ }
+
+ // iteration
+ inline bool iterate(BitMapClosure* cl, MemRegion mr);
+
+ // Return the address corresponding to the next marked bit at or after
+ // "addr", and before "limit", if "limit" is non-NULL. If there is no
+ // such bit, returns "limit" if that is non-NULL, or else "endWord()".
+ HeapWord* getNextMarkedWordAddress(const HeapWord* addr,
+ const HeapWord* limit = NULL) const;
+
+ // conversion utilities
+ HeapWord* offsetToHeapWord(size_t offset) const {
+ return _bmStartWord + (offset << _shifter);
+ }
+ size_t heapWordToOffset(const HeapWord* addr) const {
+ return pointer_delta(addr, _bmStartWord) >> _shifter;
+ }
+
+ // The argument addr should be the start address of a valid object
+ inline HeapWord* nextObject(HeapWord* addr);
+
+ void print_on_error(outputStream* st, const char* prefix) const;
+
+ // debugging
+ NOT_PRODUCT(bool covers(MemRegion rs) const;)
+};
+
+class G1CMBitMapMappingChangedListener : public G1MappingChangedListener {
+ private:
+ G1CMBitMap* _bm;
+ public:
+ G1CMBitMapMappingChangedListener() : _bm(NULL) {}
+
+ void set_bitmap(G1CMBitMap* bm) { _bm = bm; }
+
+ virtual void on_commit(uint start_idx, size_t num_regions, bool zero_filled);
+};
+
+class G1CMBitMap : public G1CMBitMapRO {
+ private:
+ G1CMBitMapMappingChangedListener _listener;
+
+ public:
+ static size_t compute_size(size_t heap_size);
+ // Returns the amount of bytes on the heap between two marks in the bitmap.
+ static size_t mark_distance();
+ // Returns how many bytes (or bits) of the heap a single byte (or bit) of the
+ // mark bitmap corresponds to. This is the same as the mark distance above.
+ static size_t heap_map_factor() {
+ return mark_distance();
+ }
+
+ G1CMBitMap() : G1CMBitMapRO(LogMinObjAlignment), _listener() { _listener.set_bitmap(this); }
+
+ // Initializes the underlying BitMap to cover the given area.
+ void initialize(MemRegion heap, G1RegionToSpaceMapper* storage);
+
+ // Write marks.
+ inline void mark(HeapWord* addr);
+ inline void clear(HeapWord* addr);
+ inline bool parMark(HeapWord* addr);
+
+ void clearRange(MemRegion mr);
+
+ // Clear the whole mark bitmap.
+ void clearAll();
+};
+
+// Represents a marking stack used by ConcurrentMarking in the G1 collector.
+class G1CMMarkStack VALUE_OBJ_CLASS_SPEC {
+ VirtualSpace _virtual_space; // Underlying backing store for actual stack
+ G1ConcurrentMark* _cm;
+ oop* _base; // bottom of stack
+ jint _index; // one more than last occupied index
+ jint _capacity; // max #elements
+ jint _saved_index; // value of _index saved at start of GC
+
+ bool _overflow;
+ bool _should_expand;
+
+ public:
+ G1CMMarkStack(G1ConcurrentMark* cm);
+ ~G1CMMarkStack();
+
+ bool allocate(size_t capacity);
+
+ // Pushes the first "n" elements of "ptr_arr" on the stack.
+ // Locking impl: concurrency is allowed only with
+ // "par_push_arr" and/or "par_pop_arr" operations, which use the same
+ // locking strategy.
+ void par_push_arr(oop* ptr_arr, int n);
+
+ // If returns false, the array was empty. Otherwise, removes up to "max"
+ // elements from the stack, and transfers them to "ptr_arr" in an
+ // unspecified order. The actual number transferred is given in "n" ("n
+ // == 0" is deliberately redundant with the return value.) Locking impl:
+ // concurrency is allowed only with "par_push_arr" and/or "par_pop_arr"
+ // operations, which use the same locking strategy.
+ bool par_pop_arr(oop* ptr_arr, int max, int* n);
+
+ bool isEmpty() { return _index == 0; }
+ int maxElems() { return _capacity; }
+
+ bool overflow() { return _overflow; }
+ void clear_overflow() { _overflow = false; }
+
+ bool should_expand() const { return _should_expand; }
+ void set_should_expand();
+
+ // Expand the stack, typically in response to an overflow condition
+ void expand();
+
+ int size() { return _index; }
+
+ void setEmpty() { _index = 0; clear_overflow(); }
+
+ // Record the current index.
+ void note_start_of_gc();
+
+ // Make sure that we have not added any entries to the stack during GC.
+ void note_end_of_gc();
+
+ // Apply fn to each oop in the mark stack, up to the bound recorded
+ // via one of the above "note" functions. The mark stack must not
+ // be modified while iterating.
+ template<typename Fn> void iterate(Fn fn);
+};
+
+class YoungList;
+
+// Root Regions are regions that are not empty at the beginning of a
+// marking cycle and which we might collect during an evacuation pause
+// while the cycle is active. Given that, during evacuation pauses, we
+// do not copy objects that are explicitly marked, what we have to do
+// for the root regions is to scan them and mark all objects reachable
+// from them. According to the SATB assumptions, we only need to visit
+// each object once during marking. So, as long as we finish this scan
+// before the next evacuation pause, we can copy the objects from the
+// root regions without having to mark them or do anything else to them.
+//
+// Currently, we only support root region scanning once (at the start
+// of the marking cycle) and the root regions are all the survivor
+// regions populated during the initial-mark pause.
+class G1CMRootRegions VALUE_OBJ_CLASS_SPEC {
+private:
+ YoungList* _young_list;
+ G1ConcurrentMark* _cm;
+
+ volatile bool _scan_in_progress;
+ volatile bool _should_abort;
+ HeapRegion* volatile _next_survivor;
+
+public:
+ G1CMRootRegions();
+ // We actually do most of the initialization in this method.
+ void init(G1CollectedHeap* g1h, G1ConcurrentMark* cm);
+
+ // Reset the claiming / scanning of the root regions.
+ void prepare_for_scan();
+
+ // Forces get_next() to return NULL so that the iteration aborts early.
+ void abort() { _should_abort = true; }
+
+ // Return true if the CM thread are actively scanning root regions,
+ // false otherwise.
+ bool scan_in_progress() { return _scan_in_progress; }
+
+ // Claim the next root region to scan atomically, or return NULL if
+ // all have been claimed.
+ HeapRegion* claim_next();
+
+ // Flag that we're done with root region scanning and notify anyone
+ // who's waiting on it. If aborted is false, assume that all regions
+ // have been claimed.
+ void scan_finished();
+
+ // If CM threads are still scanning root regions, wait until they
+ // are done. Return true if we had to wait, false otherwise.
+ bool wait_until_scan_finished();
+};
+
+class ConcurrentMarkThread;
+
+class G1ConcurrentMark: public CHeapObj<mtGC> {
+ friend class ConcurrentMarkThread;
+ friend class G1ParNoteEndTask;
+ friend class CalcLiveObjectsClosure;
+ friend class G1CMRefProcTaskProxy;
+ friend class G1CMRefProcTaskExecutor;
+ friend class G1CMKeepAliveAndDrainClosure;
+ friend class G1CMDrainMarkingStackClosure;
+ friend class G1CMBitMapClosure;
+ friend class G1CMConcurrentMarkingTask;
+ friend class G1CMMarkStack;
+ friend class G1CMRemarkTask;
+ friend class G1CMTask;
+
+protected:
+ ConcurrentMarkThread* _cmThread; // The thread doing the work
+ G1CollectedHeap* _g1h; // The heap
+ uint _parallel_marking_threads; // The number of marking
+ // threads we're using
+ uint _max_parallel_marking_threads; // Max number of marking
+ // threads we'll ever use
+ double _sleep_factor; // How much we have to sleep, with
+ // respect to the work we just did, to
+ // meet the marking overhead goal
+ double _marking_task_overhead; // Marking target overhead for
+ // a single task
+
+ FreeRegionList _cleanup_list;
+
+ // Concurrent marking support structures
+ G1CMBitMap _markBitMap1;
+ G1CMBitMap _markBitMap2;
+ G1CMBitMapRO* _prevMarkBitMap; // Completed mark bitmap
+ G1CMBitMap* _nextMarkBitMap; // Under-construction mark bitmap
+
+ BitMap _region_bm;
+ BitMap _card_bm;
+
+ // Heap bounds
+ HeapWord* _heap_start;
+ HeapWord* _heap_end;
+
+ // Root region tracking and claiming
+ G1CMRootRegions _root_regions;
+
+ // For gray objects
+ G1CMMarkStack _markStack; // Grey objects behind global finger
+ HeapWord* volatile _finger; // The global finger, region aligned,
+ // always points to the end of the
+ // last claimed region
+
+ // Marking tasks
+ uint _max_worker_id;// Maximum worker id
+ uint _active_tasks; // Task num currently active
+ G1CMTask** _tasks; // Task queue array (max_worker_id len)
+ G1CMTaskQueueSet* _task_queues; // Task queue set
+ ParallelTaskTerminator _terminator; // For termination
+
+ // Two sync barriers that are used to synchronize tasks when an
+ // overflow occurs. The algorithm is the following. All tasks enter
+ // the first one to ensure that they have all stopped manipulating
+ // the global data structures. After they exit it, they re-initialize
+ // their data structures and task 0 re-initializes the global data
+ // structures. Then, they enter the second sync barrier. This
+ // ensure, that no task starts doing work before all data
+ // structures (local and global) have been re-initialized. When they
+ // exit it, they are free to start working again.
+ WorkGangBarrierSync _first_overflow_barrier_sync;
+ WorkGangBarrierSync _second_overflow_barrier_sync;
+
+ // This is set by any task, when an overflow on the global data
+ // structures is detected
+ volatile bool _has_overflown;
+ // True: marking is concurrent, false: we're in remark
+ volatile bool _concurrent;
+ // Set at the end of a Full GC so that marking aborts
+ volatile bool _has_aborted;
+
+ // Used when remark aborts due to an overflow to indicate that
+ // another concurrent marking phase should start
+ volatile bool _restart_for_overflow;
+
+ // This is true from the very start of concurrent marking until the
+ // point when all the tasks complete their work. It is really used
+ // to determine the points between the end of concurrent marking and
+ // time of remark.
+ volatile bool _concurrent_marking_in_progress;
+
+ // Keep track of whether we have started concurrent phase or not.
+ bool _concurrent_phase_started;
+
+ // All of these times are in ms
+ NumberSeq _init_times;
+ NumberSeq _remark_times;
+ NumberSeq _remark_mark_times;
+ NumberSeq _remark_weak_ref_times;
+ NumberSeq _cleanup_times;
+ double _total_counting_time;
+ double _total_rs_scrub_time;
+
+ double* _accum_task_vtime; // Accumulated task vtime
+
+ WorkGang* _parallel_workers;
+
+ void weakRefsWorkParallelPart(BoolObjectClosure* is_alive, bool purged_classes);
+ void weakRefsWork(bool clear_all_soft_refs);
+
+ void swapMarkBitMaps();
+
+ // It resets the global marking data structures, as well as the
+ // task local ones; should be called during initial mark.
+ void reset();
+
+ // Resets all the marking data structures. Called when we have to restart
+ // marking or when marking completes (via set_non_marking_state below).
+ void reset_marking_state(bool clear_overflow = true);
+
+ // We do this after we're done with marking so that the marking data
+ // structures are initialized to a sensible and predictable state.
+ void set_non_marking_state();
+
+ // Called to indicate how many threads are currently active.
+ void set_concurrency(uint active_tasks);
+
+ // It should be called to indicate which phase we're in (concurrent
+ // mark or remark) and how many threads are currently active.
+ void set_concurrency_and_phase(uint active_tasks, bool concurrent);
+
+ // Prints all gathered CM-related statistics
+ void print_stats();
+
+ bool cleanup_list_is_empty() {
+ return _cleanup_list.is_empty();
+ }
+
+ // Accessor methods
+ uint parallel_marking_threads() const { return _parallel_marking_threads; }
+ uint max_parallel_marking_threads() const { return _max_parallel_marking_threads;}
+ double sleep_factor() { return _sleep_factor; }
+ double marking_task_overhead() { return _marking_task_overhead;}
+
+ HeapWord* finger() { return _finger; }
+ bool concurrent() { return _concurrent; }
+ uint active_tasks() { return _active_tasks; }
+ ParallelTaskTerminator* terminator() { return &_terminator; }
+
+ // It claims the next available region to be scanned by a marking
+ // task/thread. It might return NULL if the next region is empty or
+ // we have run out of regions. In the latter case, out_of_regions()
+ // determines whether we've really run out of regions or the task
+ // should call claim_region() again. This might seem a bit
+ // awkward. Originally, the code was written so that claim_region()
+ // either successfully returned with a non-empty region or there
+ // were no more regions to be claimed. The problem with this was
+ // that, in certain circumstances, it iterated over large chunks of
+ // the heap finding only empty regions and, while it was working, it
+ // was preventing the calling task to call its regular clock
+ // method. So, this way, each task will spend very little time in
+ // claim_region() and is allowed to call the regular clock method
+ // frequently.
+ HeapRegion* claim_region(uint worker_id);
+
+ // It determines whether we've run out of regions to scan. Note that
+ // the finger can point past the heap end in case the heap was expanded
+ // to satisfy an allocation without doing a GC. This is fine, because all
+ // objects in those regions will be considered live anyway because of
+ // SATB guarantees (i.e. their TAMS will be equal to bottom).
+ bool out_of_regions() { return _finger >= _heap_end; }
+
+ // Returns the task with the given id
+ G1CMTask* task(int id) {
+ assert(0 <= id && id < (int) _active_tasks,
+ "task id not within active bounds");
+ return _tasks[id];
+ }
+
+ // Returns the task queue with the given id
+ G1CMTaskQueue* task_queue(int id) {
+ assert(0 <= id && id < (int) _active_tasks,
+ "task queue id not within active bounds");
+ return (G1CMTaskQueue*) _task_queues->queue(id);
+ }
+
+ // Returns the task queue set
+ G1CMTaskQueueSet* task_queues() { return _task_queues; }
+
+ // Access / manipulation of the overflow flag which is set to
+ // indicate that the global stack has overflown
+ bool has_overflown() { return _has_overflown; }
+ void set_has_overflown() { _has_overflown = true; }
+ void clear_has_overflown() { _has_overflown = false; }
+ bool restart_for_overflow() { return _restart_for_overflow; }
+
+ // Methods to enter the two overflow sync barriers
+ void enter_first_sync_barrier(uint worker_id);
+ void enter_second_sync_barrier(uint worker_id);
+
+ // Live Data Counting data structures...
+ // These data structures are initialized at the start of
+ // marking. They are written to while marking is active.
+ // They are aggregated during remark; the aggregated values
+ // are then used to populate the _region_bm, _card_bm, and
+ // the total live bytes, which are then subsequently updated
+ // during cleanup.
+
+ // An array of bitmaps (one bit map per task). Each bitmap
+ // is used to record the cards spanned by the live objects
+ // marked by that task/worker.
+ BitMap* _count_card_bitmaps;
+
+ // Used to record the number of marked live bytes
+ // (for each region, by worker thread).
+ size_t** _count_marked_bytes;
+
+ // Card index of the bottom of the G1 heap. Used for biasing indices into
+ // the card bitmaps.
+ intptr_t _heap_bottom_card_num;
+
+ // Set to true when initialization is complete
+ bool _completed_initialization;
+
+public:
+ // Manipulation of the global mark stack.
+ // The push and pop operations are used by tasks for transfers
+ // between task-local queues and the global mark stack, and use
+ // locking for concurrency safety.
+ bool mark_stack_push(oop* arr, int n) {
+ _markStack.par_push_arr(arr, n);
+ if (_markStack.overflow()) {
+ set_has_overflown();
+ return false;
+ }
+ return true;
+ }
+ void mark_stack_pop(oop* arr, int max, int* n) {
+ _markStack.par_pop_arr(arr, max, n);
+ }
+ size_t mark_stack_size() { return _markStack.size(); }
+ size_t partial_mark_stack_size_target() { return _markStack.maxElems()/3; }
+ bool mark_stack_overflow() { return _markStack.overflow(); }
+ bool mark_stack_empty() { return _markStack.isEmpty(); }
+
+ G1CMRootRegions* root_regions() { return &_root_regions; }
+
+ bool concurrent_marking_in_progress() {
+ return _concurrent_marking_in_progress;
+ }
+ void set_concurrent_marking_in_progress() {
+ _concurrent_marking_in_progress = true;
+ }
+ void clear_concurrent_marking_in_progress() {
+ _concurrent_marking_in_progress = false;
+ }
+
+ void register_concurrent_phase_start(const char* title);
+ void register_concurrent_phase_end();
+
+ void update_accum_task_vtime(int i, double vtime) {
+ _accum_task_vtime[i] += vtime;
+ }
+
+ double all_task_accum_vtime() {
+ double ret = 0.0;
+ for (uint i = 0; i < _max_worker_id; ++i)
+ ret += _accum_task_vtime[i];
+ return ret;
+ }
+
+ // Attempts to steal an object from the task queues of other tasks
+ bool try_stealing(uint worker_id, int* hash_seed, oop& obj);
+
+ G1ConcurrentMark(G1CollectedHeap* g1h,
+ G1RegionToSpaceMapper* prev_bitmap_storage,
+ G1RegionToSpaceMapper* next_bitmap_storage);
+ ~G1ConcurrentMark();
+
+ ConcurrentMarkThread* cmThread() { return _cmThread; }
+
+ G1CMBitMapRO* prevMarkBitMap() const { return _prevMarkBitMap; }
+ G1CMBitMap* nextMarkBitMap() const { return _nextMarkBitMap; }
+
+ // Returns the number of GC threads to be used in a concurrent
+ // phase based on the number of GC threads being used in a STW
+ // phase.
+ uint scale_parallel_threads(uint n_par_threads);
+
+ // Calculates the number of GC threads to be used in a concurrent phase.
+ uint calc_parallel_marking_threads();
+
+ // The following three are interaction between CM and
+ // G1CollectedHeap
+
+ // This notifies CM that a root during initial-mark needs to be
+ // grayed. It is MT-safe. word_size is the size of the object in
+ // words. It is passed explicitly as sometimes we cannot calculate
+ // it from the given object because it might be in an inconsistent
+ // state (e.g., in to-space and being copied). So the caller is
+ // responsible for dealing with this issue (e.g., get the size from
+ // the from-space image when the to-space image might be
+ // inconsistent) and always passing the size. hr is the region that
+ // contains the object and it's passed optionally from callers who
+ // might already have it (no point in recalculating it).
+ inline void grayRoot(oop obj,
+ size_t word_size,
+ uint worker_id,
+ HeapRegion* hr = NULL);
+
+ // Clear the next marking bitmap (will be called concurrently).
+ void clearNextBitmap();
+
+ // Return whether the next mark bitmap has no marks set. To be used for assertions
+ // only. Will not yield to pause requests.
+ bool nextMarkBitmapIsClear();
+
+ // These two do the work that needs to be done before and after the
+ // initial root checkpoint. Since this checkpoint can be done at two
+ // different points (i.e. an explicit pause or piggy-backed on a
+ // young collection), then it's nice to be able to easily share the
+ // pre/post code. It might be the case that we can put everything in
+ // the post method. TP
+ void checkpointRootsInitialPre();
+ void checkpointRootsInitialPost();
+
+ // Scan all the root regions and mark everything reachable from
+ // them.
+ void scanRootRegions();
+
+ // Scan a single root region and mark everything reachable from it.
+ void scanRootRegion(HeapRegion* hr, uint worker_id);
+
+ // Do concurrent phase of marking, to a tentative transitive closure.
+ void markFromRoots();
+
+ void checkpointRootsFinal(bool clear_all_soft_refs);
+ void checkpointRootsFinalWork();
+ void cleanup();
+ void completeCleanup();
+
+ // Mark in the previous bitmap. NB: this is usually read-only, so use
+ // this carefully!
+ inline void markPrev(oop p);
+
+ // Clears marks for all objects in the given range, for the prev or
+ // next bitmaps. NB: the previous bitmap is usually
+ // read-only, so use this carefully!
+ void clearRangePrevBitmap(MemRegion mr);
+
+ // Notify data structures that a GC has started.
+ void note_start_of_gc() {
+ _markStack.note_start_of_gc();
+ }
+
+ // Notify data structures that a GC is finished.
+ void note_end_of_gc() {
+ _markStack.note_end_of_gc();
+ }
+
+ // Verify that there are no CSet oops on the stacks (taskqueues /
+ // global mark stack) and fingers (global / per-task).
+ // If marking is not in progress, it's a no-op.
+ void verify_no_cset_oops() PRODUCT_RETURN;
+
+ inline bool isPrevMarked(oop p) const;
+
+ inline bool do_yield_check(uint worker_i = 0);
+
+ // Called to abort the marking cycle after a Full GC takes place.
+ void abort();
+
+ bool has_aborted() { return _has_aborted; }
+
+ void print_summary_info();
+
+ void print_worker_threads_on(outputStream* st) const;
+
+ void print_on_error(outputStream* st) const;
+
+ // Liveness counting
+
+ // Utility routine to set an exclusive range of cards on the given
+ // card liveness bitmap
+ inline void set_card_bitmap_range(BitMap* card_bm,
+ BitMap::idx_t start_idx,
+ BitMap::idx_t end_idx,
+ bool is_par);
+
+ // Returns the card number of the bottom of the G1 heap.
+ // Used in biasing indices into accounting card bitmaps.
+ intptr_t heap_bottom_card_num() const {
+ return _heap_bottom_card_num;
+ }
+
+ // Returns the card bitmap for a given task or worker id.
+ BitMap* count_card_bitmap_for(uint worker_id) {
+ assert(worker_id < _max_worker_id, "oob");
+ assert(_count_card_bitmaps != NULL, "uninitialized");
+ BitMap* task_card_bm = &_count_card_bitmaps[worker_id];
+ assert(task_card_bm->size() == _card_bm.size(), "size mismatch");
+ return task_card_bm;
+ }
+
+ // Returns the array containing the marked bytes for each region,
+ // for the given worker or task id.
+ size_t* count_marked_bytes_array_for(uint worker_id) {
+ assert(worker_id < _max_worker_id, "oob");
+ assert(_count_marked_bytes != NULL, "uninitialized");
+ size_t* marked_bytes_array = _count_marked_bytes[worker_id];
+ assert(marked_bytes_array != NULL, "uninitialized");
+ return marked_bytes_array;
+ }
+
+ // Returns the index in the liveness accounting card table bitmap
+ // for the given address
+ inline BitMap::idx_t card_bitmap_index_for(HeapWord* addr);
+
+ // Counts the size of the given memory region in the the given
+ // marked_bytes array slot for the given HeapRegion.
+ // Sets the bits in the given card bitmap that are associated with the
+ // cards that are spanned by the memory region.
+ inline void count_region(MemRegion mr,
+ HeapRegion* hr,
+ size_t* marked_bytes_array,
+ BitMap* task_card_bm);
+
+ // Counts the given object in the given task/worker counting
+ // data structures.
+ inline void count_object(oop obj,
+ HeapRegion* hr,
+ size_t* marked_bytes_array,
+ BitMap* task_card_bm,
+ size_t word_size);
+
+ // Attempts to mark the given object and, if successful, counts
+ // the object in the given task/worker counting structures.
+ inline bool par_mark_and_count(oop obj,
+ HeapRegion* hr,
+ size_t* marked_bytes_array,
+ BitMap* task_card_bm);
+
+ // Attempts to mark the given object and, if successful, counts
+ // the object in the task/worker counting structures for the
+ // given worker id.
+ inline bool par_mark_and_count(oop obj,
+ size_t word_size,
+ HeapRegion* hr,
+ uint worker_id);
+
+ // Returns true if initialization was successfully completed.
+ bool completed_initialization() const {
+ return _completed_initialization;
+ }
+
+protected:
+ // Clear all the per-task bitmaps and arrays used to store the
+ // counting data.
+ void clear_all_count_data();
+
+ // Aggregates the counting data for each worker/task
+ // that was constructed while marking. Also sets
+ // the amount of marked bytes for each region and
+ // the top at concurrent mark count.
+ void aggregate_count_data();
+
+ // Verification routine
+ void verify_count_data();
+};
+
+// A class representing a marking task.
+class G1CMTask : public TerminatorTerminator {
+private:
+ enum PrivateConstants {
+ // the regular clock call is called once the scanned words reaches
+ // this limit
+ words_scanned_period = 12*1024,
+ // the regular clock call is called once the number of visited
+ // references reaches this limit
+ refs_reached_period = 384,
+ // initial value for the hash seed, used in the work stealing code
+ init_hash_seed = 17,
+ // how many entries will be transferred between global stack and
+ // local queues
+ global_stack_transfer_size = 16
+ };
+
+ uint _worker_id;
+ G1CollectedHeap* _g1h;
+ G1ConcurrentMark* _cm;
+ G1CMBitMap* _nextMarkBitMap;
+ // the task queue of this task
+ G1CMTaskQueue* _task_queue;
+private:
+ // the task queue set---needed for stealing
+ G1CMTaskQueueSet* _task_queues;
+ // indicates whether the task has been claimed---this is only for
+ // debugging purposes
+ bool _claimed;
+
+ // number of calls to this task
+ int _calls;
+
+ // when the virtual timer reaches this time, the marking step should
+ // exit
+ double _time_target_ms;
+ // the start time of the current marking step
+ double _start_time_ms;
+
+ // the oop closure used for iterations over oops
+ G1CMOopClosure* _cm_oop_closure;
+
+ // the region this task is scanning, NULL if we're not scanning any
+ HeapRegion* _curr_region;
+ // the local finger of this task, NULL if we're not scanning a region
+ HeapWord* _finger;
+ // limit of the region this task is scanning, NULL if we're not scanning one
+ HeapWord* _region_limit;
+
+ // the number of words this task has scanned
+ size_t _words_scanned;
+ // When _words_scanned reaches this limit, the regular clock is
+ // called. Notice that this might be decreased under certain
+ // circumstances (i.e. when we believe that we did an expensive
+ // operation).
+ size_t _words_scanned_limit;
+ // the initial value of _words_scanned_limit (i.e. what it was
+ // before it was decreased).
+ size_t _real_words_scanned_limit;
+
+ // the number of references this task has visited
+ size_t _refs_reached;
+ // When _refs_reached reaches this limit, the regular clock is
+ // called. Notice this this might be decreased under certain
+ // circumstances (i.e. when we believe that we did an expensive
+ // operation).
+ size_t _refs_reached_limit;
+ // the initial value of _refs_reached_limit (i.e. what it was before
+ // it was decreased).
+ size_t _real_refs_reached_limit;
+
+ // used by the work stealing stuff
+ int _hash_seed;
+ // if this is true, then the task has aborted for some reason
+ bool _has_aborted;
+ // set when the task aborts because it has met its time quota
+ bool _has_timed_out;
+ // true when we're draining SATB buffers; this avoids the task
+ // aborting due to SATB buffers being available (as we're already
+ // dealing with them)
+ bool _draining_satb_buffers;
+
+ // number sequence of past step times
+ NumberSeq _step_times_ms;
+ // elapsed time of this task
+ double _elapsed_time_ms;
+ // termination time of this task
+ double _termination_time_ms;
+ // when this task got into the termination protocol
+ double _termination_start_time_ms;
+
+ // true when the task is during a concurrent phase, false when it is
+ // in the remark phase (so, in the latter case, we do not have to
+ // check all the things that we have to check during the concurrent
+ // phase, i.e. SATB buffer availability...)
+ bool _concurrent;
+
+ TruncatedSeq _marking_step_diffs_ms;
+
+ // Counting data structures. Embedding the task's marked_bytes_array
+ // and card bitmap into the actual task saves having to go through
+ // the ConcurrentMark object.
+ size_t* _marked_bytes_array;
+ BitMap* _card_bm;
+
+ // it updates the local fields after this task has claimed
+ // a new region to scan
+ void setup_for_region(HeapRegion* hr);
+ // it brings up-to-date the limit of the region
+ void update_region_limit();
+
+ // called when either the words scanned or the refs visited limit
+ // has been reached
+ void reached_limit();
+ // recalculates the words scanned and refs visited limits
+ void recalculate_limits();
+ // decreases the words scanned and refs visited limits when we reach
+ // an expensive operation
+ void decrease_limits();
+ // it checks whether the words scanned or refs visited reached their
+ // respective limit and calls reached_limit() if they have
+ void check_limits() {
+ if (_words_scanned >= _words_scanned_limit ||
+ _refs_reached >= _refs_reached_limit) {
+ reached_limit();
+ }
+ }
+ // this is supposed to be called regularly during a marking step as
+ // it checks a bunch of conditions that might cause the marking step
+ // to abort
+ void regular_clock_call();
+ bool concurrent() { return _concurrent; }
+
+ // Test whether obj might have already been passed over by the
+ // mark bitmap scan, and so needs to be pushed onto the mark stack.
+ bool is_below_finger(oop obj, HeapWord* global_finger) const;
+
+ template<bool scan> void process_grey_object(oop obj);
+
+public:
+ // It resets the task; it should be called right at the beginning of
+ // a marking phase.
+ void reset(G1CMBitMap* _nextMarkBitMap);
+ // it clears all the fields that correspond to a claimed region.
+ void clear_region_fields();
+
+ void set_concurrent(bool concurrent) { _concurrent = concurrent; }
+
+ // The main method of this class which performs a marking step
+ // trying not to exceed the given duration. However, it might exit
+ // prematurely, according to some conditions (i.e. SATB buffers are
+ // available for processing).
+ void do_marking_step(double target_ms,
+ bool do_termination,
+ bool is_serial);
+
+ // These two calls start and stop the timer
+ void record_start_time() {
+ _elapsed_time_ms = os::elapsedTime() * 1000.0;
+ }
+ void record_end_time() {
+ _elapsed_time_ms = os::elapsedTime() * 1000.0 - _elapsed_time_ms;
+ }
+
+ // returns the worker ID associated with this task.
+ uint worker_id() { return _worker_id; }
+
+ // From TerminatorTerminator. It determines whether this task should
+ // exit the termination protocol after it's entered it.
+ virtual bool should_exit_termination();
+
+ // Resets the local region fields after a task has finished scanning a
+ // region; or when they have become stale as a result of the region
+ // being evacuated.
+ void giveup_current_region();
+
+ HeapWord* finger() { return _finger; }
+
+ bool has_aborted() { return _has_aborted; }
+ void set_has_aborted() { _has_aborted = true; }
+ void clear_has_aborted() { _has_aborted = false; }
+ bool has_timed_out() { return _has_timed_out; }
+ bool claimed() { return _claimed; }
+
+ void set_cm_oop_closure(G1CMOopClosure* cm_oop_closure);
+
+ // Increment the number of references this task has visited.
+ void increment_refs_reached() { ++_refs_reached; }
+
+ // Grey the object by marking it. If not already marked, push it on
+ // the local queue if below the finger.
+ // Precondition: obj is in region.
+ // Precondition: obj is below region's NTAMS.
+ inline void make_reference_grey(oop obj, HeapRegion* region);
+
+ // Grey the object (by calling make_grey_reference) if required,
+ // e.g. obj is below its containing region's NTAMS.
+ // Precondition: obj is a valid heap object.
+ inline void deal_with_reference(oop obj);
+
+ // It scans an object and visits its children.
+ inline void scan_object(oop obj);
+
+ // It pushes an object on the local queue.
+ inline void push(oop obj);
+
+ // These two move entries to/from the global stack.
+ void move_entries_to_global_stack();
+ void get_entries_from_global_stack();
+
+ // It pops and scans objects from the local queue. If partially is
+ // true, then it stops when the queue size is of a given limit. If
+ // partially is false, then it stops when the queue is empty.
+ void drain_local_queue(bool partially);
+ // It moves entries from the global stack to the local queue and
+ // drains the local queue. If partially is true, then it stops when
+ // both the global stack and the local queue reach a given size. If
+ // partially if false, it tries to empty them totally.
+ void drain_global_stack(bool partially);
+ // It keeps picking SATB buffers and processing them until no SATB
+ // buffers are available.
+ void drain_satb_buffers();
+
+ // moves the local finger to a new location
+ inline void move_finger_to(HeapWord* new_finger) {
+ assert(new_finger >= _finger && new_finger < _region_limit, "invariant");
+ _finger = new_finger;
+ }
+
+ G1CMTask(uint worker_id,
+ G1ConcurrentMark *cm,
+ size_t* marked_bytes,
+ BitMap* card_bm,
+ G1CMTaskQueue* task_queue,
+ G1CMTaskQueueSet* task_queues);
+
+ // it prints statistics associated with this task
+ void print_stats();
+};
+
+// Class that's used to to print out per-region liveness
+// information. It's currently used at the end of marking and also
+// after we sort the old regions at the end of the cleanup operation.
+class G1PrintRegionLivenessInfoClosure: public HeapRegionClosure {
+private:
+ // Accumulators for these values.
+ size_t _total_used_bytes;
+ size_t _total_capacity_bytes;
+ size_t _total_prev_live_bytes;
+ size_t _total_next_live_bytes;
+
+ // These are set up when we come across a "stars humongous" region
+ // (as this is where most of this information is stored, not in the
+ // subsequent "continues humongous" regions). After that, for every
+ // region in a given humongous region series we deduce the right
+ // values for it by simply subtracting the appropriate amount from
+ // these fields. All these values should reach 0 after we've visited
+ // the last region in the series.
+ size_t _hum_used_bytes;
+ size_t _hum_capacity_bytes;
+ size_t _hum_prev_live_bytes;
+ size_t _hum_next_live_bytes;
+
+ // Accumulator for the remembered set size
+ size_t _total_remset_bytes;
+
+ // Accumulator for strong code roots memory size
+ size_t _total_strong_code_roots_bytes;
+
+ static double perc(size_t val, size_t total) {
+ if (total == 0) {
+ return 0.0;
+ } else {
+ return 100.0 * ((double) val / (double) total);
+ }
+ }
+
+ static double bytes_to_mb(size_t val) {
+ return (double) val / (double) M;
+ }
+
+ // See the .cpp file.
+ size_t get_hum_bytes(size_t* hum_bytes);
+ void get_hum_bytes(size_t* used_bytes, size_t* capacity_bytes,
+ size_t* prev_live_bytes, size_t* next_live_bytes);
+
+public:
+ // The header and footer are printed in the constructor and
+ // destructor respectively.
+ G1PrintRegionLivenessInfoClosure(const char* phase_name);
+ virtual bool doHeapRegion(HeapRegion* r);
+ ~G1PrintRegionLivenessInfoClosure();
+};
+
+#endif // SHARE_VM_GC_G1_G1CONCURRENTMARK_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,394 @@
+/*
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1CONCURRENTMARK_INLINE_HPP
+#define SHARE_VM_GC_G1_G1CONCURRENTMARK_INLINE_HPP
+
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1ConcurrentMark.hpp"
+#include "gc/shared/taskqueue.inline.hpp"
+
+// Utility routine to set an exclusive range of cards on the given
+// card liveness bitmap
+inline void G1ConcurrentMark::set_card_bitmap_range(BitMap* card_bm,
+ BitMap::idx_t start_idx,
+ BitMap::idx_t end_idx,
+ bool is_par) {
+
+ // Set the exclusive bit range [start_idx, end_idx).
+ assert((end_idx - start_idx) > 0, "at least one card");
+ assert(end_idx <= card_bm->size(), "sanity");
+
+ // Silently clip the end index
+ end_idx = MIN2(end_idx, card_bm->size());
+
+ // For small ranges use a simple loop; otherwise use set_range or
+ // use par_at_put_range (if parallel). The range is made up of the
+ // cards that are spanned by an object/mem region so 8 cards will
+ // allow up to object sizes up to 4K to be handled using the loop.
+ if ((end_idx - start_idx) <= 8) {
+ for (BitMap::idx_t i = start_idx; i < end_idx; i += 1) {
+ if (is_par) {
+ card_bm->par_set_bit(i);
+ } else {
+ card_bm->set_bit(i);
+ }
+ }
+ } else {
+ // Note BitMap::par_at_put_range() and BitMap::set_range() are exclusive.
+ if (is_par) {
+ card_bm->par_at_put_range(start_idx, end_idx, true);
+ } else {
+ card_bm->set_range(start_idx, end_idx);
+ }
+ }
+}
+
+// Returns the index in the liveness accounting card bitmap
+// for the given address
+inline BitMap::idx_t G1ConcurrentMark::card_bitmap_index_for(HeapWord* addr) {
+ // Below, the term "card num" means the result of shifting an address
+ // by the card shift -- address 0 corresponds to card number 0. One
+ // must subtract the card num of the bottom of the heap to obtain a
+ // card table index.
+ intptr_t card_num = intptr_t(uintptr_t(addr) >> CardTableModRefBS::card_shift);
+ return card_num - heap_bottom_card_num();
+}
+
+// Counts the given memory region in the given task/worker
+// counting data structures.
+inline void G1ConcurrentMark::count_region(MemRegion mr, HeapRegion* hr,
+ size_t* marked_bytes_array,
+ BitMap* task_card_bm) {
+ G1CollectedHeap* g1h = _g1h;
+ CardTableModRefBS* ct_bs = g1h->g1_barrier_set();
+
+ HeapWord* start = mr.start();
+ HeapWord* end = mr.end();
+ size_t region_size_bytes = mr.byte_size();
+ uint index = hr->hrm_index();
+
+ assert(hr == g1h->heap_region_containing(start), "sanity");
+ assert(marked_bytes_array != NULL, "pre-condition");
+ assert(task_card_bm != NULL, "pre-condition");
+
+ // Add to the task local marked bytes for this region.
+ marked_bytes_array[index] += region_size_bytes;
+
+ BitMap::idx_t start_idx = card_bitmap_index_for(start);
+ BitMap::idx_t end_idx = card_bitmap_index_for(end);
+
+ // Note: if we're looking at the last region in heap - end
+ // could be actually just beyond the end of the heap; end_idx
+ // will then correspond to a (non-existent) card that is also
+ // just beyond the heap.
+ if (g1h->is_in_g1_reserved(end) && !ct_bs->is_card_aligned(end)) {
+ // end of region is not card aligned - increment to cover
+ // all the cards spanned by the region.
+ end_idx += 1;
+ }
+ // The card bitmap is task/worker specific => no need to use
+ // the 'par' BitMap routines.
+ // Set bits in the exclusive bit range [start_idx, end_idx).
+ set_card_bitmap_range(task_card_bm, start_idx, end_idx, false /* is_par */);
+}
+
+// Counts the given object in the given task/worker counting data structures.
+inline void G1ConcurrentMark::count_object(oop obj,
+ HeapRegion* hr,
+ size_t* marked_bytes_array,
+ BitMap* task_card_bm,
+ size_t word_size) {
+ assert(!hr->is_continues_humongous(), "Cannot enter count_object with continues humongous");
+ if (!hr->is_starts_humongous()) {
+ MemRegion mr((HeapWord*)obj, word_size);
+ count_region(mr, hr, marked_bytes_array, task_card_bm);
+ } else {
+ do {
+ MemRegion mr(hr->bottom(), hr->top());
+ count_region(mr, hr, marked_bytes_array, task_card_bm);
+ hr = _g1h->next_region_in_humongous(hr);
+ } while (hr != NULL);
+ }
+}
+
+// Attempts to mark the given object and, if successful, counts
+// the object in the given task/worker counting structures.
+inline bool G1ConcurrentMark::par_mark_and_count(oop obj,
+ HeapRegion* hr,
+ size_t* marked_bytes_array,
+ BitMap* task_card_bm) {
+ if (_nextMarkBitMap->parMark((HeapWord*)obj)) {
+ // Update the task specific count data for the object.
+ count_object(obj, hr, marked_bytes_array, task_card_bm, obj->size());
+ return true;
+ }
+ return false;
+}
+
+// Attempts to mark the given object and, if successful, counts
+// the object in the task/worker counting structures for the
+// given worker id.
+inline bool G1ConcurrentMark::par_mark_and_count(oop obj,
+ size_t word_size,
+ HeapRegion* hr,
+ uint worker_id) {
+ if (_nextMarkBitMap->parMark((HeapWord*)obj)) {
+ size_t* marked_bytes_array = count_marked_bytes_array_for(worker_id);
+ BitMap* task_card_bm = count_card_bitmap_for(worker_id);
+ count_object(obj, hr, marked_bytes_array, task_card_bm, word_size);
+ return true;
+ }
+ return false;
+}
+
+inline bool G1CMBitMapRO::iterate(BitMapClosure* cl, MemRegion mr) {
+ HeapWord* start_addr = MAX2(startWord(), mr.start());
+ HeapWord* end_addr = MIN2(endWord(), mr.end());
+
+ if (end_addr > start_addr) {
+ // Right-open interval [start-offset, end-offset).
+ BitMap::idx_t start_offset = heapWordToOffset(start_addr);
+ BitMap::idx_t end_offset = heapWordToOffset(end_addr);
+
+ start_offset = _bm.get_next_one_offset(start_offset, end_offset);
+ while (start_offset < end_offset) {
+ if (!cl->do_bit(start_offset)) {
+ return false;
+ }
+ HeapWord* next_addr = MIN2(nextObject(offsetToHeapWord(start_offset)), end_addr);
+ BitMap::idx_t next_offset = heapWordToOffset(next_addr);
+ start_offset = _bm.get_next_one_offset(next_offset, end_offset);
+ }
+ }
+ return true;
+}
+
+// The argument addr should be the start address of a valid object
+HeapWord* G1CMBitMapRO::nextObject(HeapWord* addr) {
+ oop obj = (oop) addr;
+ HeapWord* res = addr + obj->size();
+ assert(offsetToHeapWord(heapWordToOffset(res)) == res, "sanity");
+ return res;
+}
+
+#define check_mark(addr) \
+ assert(_bmStartWord <= (addr) && (addr) < (_bmStartWord + _bmWordSize), \
+ "outside underlying space?"); \
+ assert(G1CollectedHeap::heap()->is_in_exact(addr), \
+ "Trying to access not available bitmap " PTR_FORMAT \
+ " corresponding to " PTR_FORMAT " (%u)", \
+ p2i(this), p2i(addr), G1CollectedHeap::heap()->addr_to_region(addr));
+
+inline void G1CMBitMap::mark(HeapWord* addr) {
+ check_mark(addr);
+ _bm.set_bit(heapWordToOffset(addr));
+}
+
+inline void G1CMBitMap::clear(HeapWord* addr) {
+ check_mark(addr);
+ _bm.clear_bit(heapWordToOffset(addr));
+}
+
+inline bool G1CMBitMap::parMark(HeapWord* addr) {
+ check_mark(addr);
+ return _bm.par_set_bit(heapWordToOffset(addr));
+}
+
+#undef check_mark
+
+template<typename Fn>
+inline void G1CMMarkStack::iterate(Fn fn) {
+ assert(_saved_index == _index, "saved index: %d index: %d", _saved_index, _index);
+ for (int i = 0; i < _index; ++i) {
+ fn(_base[i]);
+ }
+}
+
+// It scans an object and visits its children.
+inline void G1CMTask::scan_object(oop obj) { process_grey_object<true>(obj); }
+
+inline void G1CMTask::push(oop obj) {
+ HeapWord* objAddr = (HeapWord*) obj;
+ assert(_g1h->is_in_g1_reserved(objAddr), "invariant");
+ assert(!_g1h->is_on_master_free_list(
+ _g1h->heap_region_containing((HeapWord*) objAddr)), "invariant");
+ assert(!_g1h->is_obj_ill(obj), "invariant");
+ assert(_nextMarkBitMap->isMarked(objAddr), "invariant");
+
+ if (!_task_queue->push(obj)) {
+ // The local task queue looks full. We need to push some entries
+ // to the global stack.
+ move_entries_to_global_stack();
+
+ // this should succeed since, even if we overflow the global
+ // stack, we should have definitely removed some entries from the
+ // local queue. So, there must be space on it.
+ bool success = _task_queue->push(obj);
+ assert(success, "invariant");
+ }
+}
+
+inline bool G1CMTask::is_below_finger(oop obj, HeapWord* global_finger) const {
+ // If obj is above the global finger, then the mark bitmap scan
+ // will find it later, and no push is needed. Similarly, if we have
+ // a current region and obj is between the local finger and the
+ // end of the current region, then no push is needed. The tradeoff
+ // of checking both vs only checking the global finger is that the
+ // local check will be more accurate and so result in fewer pushes,
+ // but may also be a little slower.
+ HeapWord* objAddr = (HeapWord*)obj;
+ if (_finger != NULL) {
+ // We have a current region.
+
+ // Finger and region values are all NULL or all non-NULL. We
+ // use _finger to check since we immediately use its value.
+ assert(_curr_region != NULL, "invariant");
+ assert(_region_limit != NULL, "invariant");
+ assert(_region_limit <= global_finger, "invariant");
+
+ // True if obj is less than the local finger, or is between
+ // the region limit and the global finger.
+ if (objAddr < _finger) {
+ return true;
+ } else if (objAddr < _region_limit) {
+ return false;
+ } // Else check global finger.
+ }
+ // Check global finger.
+ return objAddr < global_finger;
+}
+
+template<bool scan>
+inline void G1CMTask::process_grey_object(oop obj) {
+ assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray");
+ assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
+
+ size_t obj_size = obj->size();
+ _words_scanned += obj_size;
+
+ if (scan) {
+ obj->oop_iterate(_cm_oop_closure);
+ }
+ check_limits();
+}
+
+
+
+inline void G1CMTask::make_reference_grey(oop obj, HeapRegion* hr) {
+ if (_cm->par_mark_and_count(obj, hr, _marked_bytes_array, _card_bm)) {
+ // No OrderAccess:store_load() is needed. It is implicit in the
+ // CAS done in G1CMBitMap::parMark() call in the routine above.
+ HeapWord* global_finger = _cm->finger();
+
+ // We only need to push a newly grey object on the mark
+ // stack if it is in a section of memory the mark bitmap
+ // scan has already examined. Mark bitmap scanning
+ // maintains progress "fingers" for determining that.
+ //
+ // Notice that the global finger might be moving forward
+ // concurrently. This is not a problem. In the worst case, we
+ // mark the object while it is above the global finger and, by
+ // the time we read the global finger, it has moved forward
+ // past this object. In this case, the object will probably
+ // be visited when a task is scanning the region and will also
+ // be pushed on the stack. So, some duplicate work, but no
+ // correctness problems.
+ if (is_below_finger(obj, global_finger)) {
+ if (obj->is_typeArray()) {
+ // Immediately process arrays of primitive types, rather
+ // than pushing on the mark stack. This keeps us from
+ // adding humongous objects to the mark stack that might
+ // be reclaimed before the entry is processed - see
+ // selection of candidates for eager reclaim of humongous
+ // objects. The cost of the additional type test is
+ // mitigated by avoiding a trip through the mark stack,
+ // by only doing a bookkeeping update and avoiding the
+ // actual scan of the object - a typeArray contains no
+ // references, and the metadata is built-in.
+ process_grey_object<false>(obj);
+ } else {
+ push(obj);
+ }
+ }
+ }
+}
+
+inline void G1CMTask::deal_with_reference(oop obj) {
+ increment_refs_reached();
+
+ HeapWord* objAddr = (HeapWord*) obj;
+ assert(obj->is_oop_or_null(true /* ignore mark word */), "Expected an oop or NULL at " PTR_FORMAT, p2i(obj));
+ if (_g1h->is_in_g1_reserved(objAddr)) {
+ assert(obj != NULL, "null check is implicit");
+ if (!_nextMarkBitMap->isMarked(objAddr)) {
+ // Only get the containing region if the object is not marked on the
+ // bitmap (otherwise, it's a waste of time since we won't do
+ // anything with it).
+ HeapRegion* hr = _g1h->heap_region_containing(obj);
+ if (!hr->obj_allocated_since_next_marking(obj)) {
+ make_reference_grey(obj, hr);
+ }
+ }
+ }
+}
+
+inline void G1ConcurrentMark::markPrev(oop p) {
+ assert(!_prevMarkBitMap->isMarked((HeapWord*) p), "sanity");
+ // Note we are overriding the read-only view of the prev map here, via
+ // the cast.
+ ((G1CMBitMap*)_prevMarkBitMap)->mark((HeapWord*) p);
+}
+
+bool G1ConcurrentMark::isPrevMarked(oop p) const {
+ assert(p != NULL && p->is_oop(), "expected an oop");
+ HeapWord* addr = (HeapWord*)p;
+ assert(addr >= _prevMarkBitMap->startWord() ||
+ addr < _prevMarkBitMap->endWord(), "in a region");
+
+ return _prevMarkBitMap->isMarked(addr);
+}
+
+inline void G1ConcurrentMark::grayRoot(oop obj, size_t word_size,
+ uint worker_id, HeapRegion* hr) {
+ assert(obj != NULL, "pre-condition");
+ HeapWord* addr = (HeapWord*) obj;
+ if (hr == NULL) {
+ hr = _g1h->heap_region_containing(addr);
+ } else {
+ assert(hr->is_in(addr), "pre-condition");
+ }
+ assert(hr != NULL, "sanity");
+ // Given that we're looking for a region that contains an object
+ // header it's impossible to get back a HC region.
+ assert(!hr->is_continues_humongous(), "sanity");
+
+ if (addr < hr->next_top_at_mark_start()) {
+ if (!_nextMarkBitMap->isMarked(addr)) {
+ par_mark_and_count(obj, word_size, hr, worker_id);
+ }
+ }
+}
+
+#endif // SHARE_VM_GC_G1_G1CONCURRENTMARK_INLINE_HPP
--- a/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -23,11 +23,12 @@
*/
#include "precompiled.hpp"
-#include "gc/g1/concurrentMark.inline.hpp"
#include "gc/g1/dirtyCardQueue.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorState.hpp"
+#include "gc/g1/g1ConcurrentMark.inline.hpp"
#include "gc/g1/g1EvacFailure.hpp"
+#include "gc/g1/g1HeapVerifier.hpp"
#include "gc/g1/g1OopClosures.inline.hpp"
#include "gc/g1/g1_globals.hpp"
#include "gc/g1/heapRegion.hpp"
@@ -61,7 +62,7 @@
class RemoveSelfForwardPtrObjClosure: public ObjectClosure {
private:
G1CollectedHeap* _g1;
- ConcurrentMark* _cm;
+ G1ConcurrentMark* _cm;
HeapRegion* _hr;
size_t _marked_bytes;
OopsInHeapRegionClosure *_update_rset_cl;
@@ -223,7 +224,7 @@
if (hr->evacuation_failed()) {
hr->note_self_forwarding_removal_start(during_initial_mark,
during_conc_mark);
- _g1h->check_bitmaps("Self-Forwarding Ptr Removal", hr);
+ _g1h->verifier()->check_bitmaps("Self-Forwarding Ptr Removal", hr);
// In the common case (i.e. when there is no evacuation
// failure) we make sure that the following is done when
--- a/hotspot/src/share/vm/gc/g1/g1EvacFailure.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1EvacFailure.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
--- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -30,6 +30,7 @@
#include "gc/g1/workerDataArray.inline.hpp"
#include "memory/allocation.hpp"
#include "logging/log.hpp"
+#include "runtime/timer.hpp"
#include "runtime/os.hpp"
// Helper class for avoiding interleaved logging
@@ -125,7 +126,7 @@
_gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray<double>(max_gc_threads, "Queue Fixup:", true, 2);
_gc_par_phases[StringDedupTableFixup] = new WorkerDataArray<double>(max_gc_threads, "Table Fixup:", true, 2);
- _gc_par_phases[RedirtyCards] = new WorkerDataArray<double>(max_gc_threads, "Parallel Redirty", true, 3);
+ _gc_par_phases[RedirtyCards] = new WorkerDataArray<double>(max_gc_threads, "Parallel Redirty:", true, 3);
_redirtied_cards = new WorkerDataArray<size_t>(max_gc_threads, "Redirtied Cards:", true, 3);
_gc_par_phases[RedirtyCards]->link_thread_work_items(_redirtied_cards);
}
@@ -133,6 +134,7 @@
void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) {
assert(active_gc_threads > 0, "The number of threads must be > 0");
assert(active_gc_threads <= _max_gc_threads, "The number of active threads must be <= the max number of threads");
+ _gc_start_counter = os::elapsed_counter();
_active_gc_threads = active_gc_threads;
_cur_expand_heap_time_ms = 0.0;
_external_accounted_time_ms = 0.0;
@@ -146,6 +148,7 @@
}
void G1GCPhaseTimes::note_gc_end() {
+ _gc_pause_time_ms = TimeHelper::counter_to_millis(os::elapsed_counter() - _gc_start_counter);
for (uint i = 0; i < _active_gc_threads; i++) {
double worker_time = _gc_par_phases[GCWorkerEnd]->get(i) - _gc_par_phases[GCWorkerStart]->get(i);
record_time_secs(GCWorkerTotal, i , worker_time);
@@ -349,7 +352,7 @@
}
};
-void G1GCPhaseTimes::print(double pause_time_ms) {
+void G1GCPhaseTimes::print() {
note_gc_end();
G1GCParPhasePrinter par_phase_printer(this);
@@ -373,7 +376,7 @@
}
print_stats(Indents[1], "Clear CT", _cur_clear_ct_time_ms);
print_stats(Indents[1], "Expand Heap After Collection", _cur_expand_heap_time_ms);
- double misc_time_ms = pause_time_ms - accounted_time_ms();
+ double misc_time_ms = _gc_pause_time_ms - accounted_time_ms();
print_stats(Indents[1], "Other", misc_time_ms);
if (_cur_verify_before_time_ms > 0.0) {
print_stats(Indents[2], "Verify Before", _cur_verify_before_time_ms);
--- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -36,6 +36,8 @@
uint _active_gc_threads;
uint _max_gc_threads;
+ jlong _gc_start_counter;
+ double _gc_pause_time_ms;
public:
enum GCParPhases {
@@ -126,7 +128,7 @@
public:
G1GCPhaseTimes(uint max_gc_threads);
void note_gc_start(uint active_gc_threads);
- void print(double pause_time_ms);
+ void print();
// record the time a phase took in seconds
void record_time_secs(GCParPhases phase, uint worker_i, double secs);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1HeapTransition.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/g1CollectorPolicy.hpp"
+#include "gc/g1/g1HeapTransition.hpp"
+#include "logging/log.hpp"
+#include "memory/metaspace.hpp"
+
+G1HeapTransition::Data::Data(G1CollectedHeap* g1_heap) {
+ YoungList* young_list = g1_heap->young_list();
+ _eden_length = young_list->eden_length();
+ _survivor_length = young_list->survivor_length();
+ _old_length = g1_heap->old_regions_count();
+ _humongous_length = g1_heap->humongous_regions_count();
+ _metaspace_used_bytes = MetaspaceAux::used_bytes();
+}
+
+G1HeapTransition::G1HeapTransition(G1CollectedHeap* g1_heap) : _g1_heap(g1_heap), _before(g1_heap) { }
+
+struct DetailedUsage : public StackObj {
+ size_t _eden_used;
+ size_t _survivor_used;
+ size_t _old_used;
+ size_t _humongous_used;
+
+ size_t _eden_region_count;
+ size_t _survivor_region_count;
+ size_t _old_region_count;
+ size_t _humongous_region_count;
+
+ DetailedUsage() :
+ _eden_used(0), _survivor_used(0), _old_used(0), _humongous_used(0),
+ _eden_region_count(0), _survivor_region_count(0), _old_region_count(0), _humongous_region_count(0) {}
+};
+
+class DetailedUsageClosure: public HeapRegionClosure {
+public:
+ DetailedUsage _usage;
+ bool doHeapRegion(HeapRegion* r) {
+ if (r->is_old()) {
+ _usage._old_used += r->used();
+ _usage._old_region_count++;
+ } else if (r->is_survivor()) {
+ _usage._survivor_used += r->used();
+ _usage._survivor_region_count++;
+ } else if (r->is_eden()) {
+ _usage._eden_used += r->used();
+ _usage._eden_region_count++;
+ } else if (r->is_humongous()) {
+ _usage._humongous_used += r->used();
+ _usage._humongous_region_count++;
+ } else {
+ assert(r->used() == 0, "Expected used to be 0 but it was " SIZE_FORMAT, r->used());
+ }
+ return false;
+ }
+};
+
+void G1HeapTransition::print() {
+ Data after(_g1_heap);
+
+ size_t eden_capacity_bytes_after_gc = _g1_heap->g1_policy()->young_list_target_length() - after._survivor_length;
+ size_t survivor_capacity_bytes_after_gc = _g1_heap->g1_policy()->max_survivor_regions();
+
+ DetailedUsage usage;
+ if (log_is_enabled(Trace, gc, heap)) {
+ DetailedUsageClosure blk;
+ _g1_heap->heap_region_iterate(&blk);
+ usage = blk._usage;
+ assert(usage._eden_region_count == 0, "Expected no eden regions, but got " SIZE_FORMAT, usage._eden_region_count);
+ assert(usage._survivor_region_count == after._survivor_length, "Expected survivors to be " SIZE_FORMAT " but was " SIZE_FORMAT,
+ after._survivor_length, usage._survivor_region_count);
+ assert(usage._old_region_count == after._old_length, "Expected old to be " SIZE_FORMAT " but was " SIZE_FORMAT,
+ after._old_length, usage._old_region_count);
+ assert(usage._humongous_region_count == after._humongous_length, "Expected humongous to be " SIZE_FORMAT " but was " SIZE_FORMAT,
+ after._humongous_length, usage._humongous_region_count);
+ }
+
+ log_info(gc, heap)("Eden regions: " SIZE_FORMAT "->" SIZE_FORMAT "(" SIZE_FORMAT ")",
+ _before._eden_length, after._eden_length, eden_capacity_bytes_after_gc);
+ log_trace(gc, heap)(" Used: 0K, Waste: 0K");
+
+ log_info(gc, heap)("Survivor regions: " SIZE_FORMAT "->" SIZE_FORMAT "(" SIZE_FORMAT ")",
+ _before._survivor_length, after._survivor_length, survivor_capacity_bytes_after_gc);
+ log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K",
+ usage._survivor_used / K, ((after._survivor_length * HeapRegion::GrainBytes) - usage._survivor_used) / K);
+
+ log_info(gc, heap)("Old regions: " SIZE_FORMAT "->" SIZE_FORMAT,
+ _before._old_length, after._old_length);
+ log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K",
+ usage._old_used / K, ((after._old_length * HeapRegion::GrainBytes) - usage._old_used) / K);
+
+ log_info(gc, heap)("Humongous regions: " SIZE_FORMAT "->" SIZE_FORMAT,
+ _before._humongous_length, after._humongous_length);
+ log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K",
+ usage._humongous_used / K, ((after._humongous_length * HeapRegion::GrainBytes) - usage._humongous_used) / K);
+
+ MetaspaceAux::print_metaspace_change(_before._metaspace_used_bytes);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1HeapTransition.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1HEAPTRANSITION_HPP
+#define SHARE_VM_GC_G1_G1HEAPTRANSITION_HPP
+
+#include "gc/shared/plab.hpp"
+
+class G1CollectedHeap;
+
+class G1HeapTransition {
+ struct Data {
+ size_t _eden_length;
+ size_t _survivor_length;
+ size_t _old_length;
+ size_t _humongous_length;
+ size_t _metaspace_used_bytes;
+
+ Data(G1CollectedHeap* g1_heap);
+ };
+
+ G1CollectedHeap* _g1_heap;
+ Data _before;
+
+public:
+ G1HeapTransition(G1CollectedHeap* g1_heap);
+
+ void print();
+};
+
+#endif // SHARE_VM_GC_G1_G1HEAPTRANSITION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,731 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "logging/log.hpp"
+#include "gc/g1/concurrentMarkThread.hpp"
+#include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1HeapVerifier.hpp"
+#include "gc/g1/g1MarkSweep.hpp"
+#include "gc/g1/g1RemSet.hpp"
+#include "gc/g1/g1RootProcessor.hpp"
+#include "gc/g1/heapRegion.hpp"
+#include "gc/g1/heapRegion.inline.hpp"
+#include "gc/g1/heapRegionRemSet.hpp"
+#include "gc/g1/g1StringDedup.hpp"
+#include "gc/g1/youngList.hpp"
+#include "memory/resourceArea.hpp"
+#include "oops/oop.inline.hpp"
+
+class VerifyRootsClosure: public OopClosure {
+private:
+ G1CollectedHeap* _g1h;
+ VerifyOption _vo;
+ bool _failures;
+public:
+ // _vo == UsePrevMarking -> use "prev" marking information,
+ // _vo == UseNextMarking -> use "next" marking information,
+ // _vo == UseMarkWord -> use mark word from object header.
+ VerifyRootsClosure(VerifyOption vo) :
+ _g1h(G1CollectedHeap::heap()),
+ _vo(vo),
+ _failures(false) { }
+
+ bool failures() { return _failures; }
+
+ template <class T> void do_oop_nv(T* p) {
+ T heap_oop = oopDesc::load_heap_oop(p);
+ if (!oopDesc::is_null(heap_oop)) {
+ oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
+ if (_g1h->is_obj_dead_cond(obj, _vo)) {
+ LogHandle(gc, verify) log;
+ log.info("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj));
+ if (_vo == VerifyOption_G1UseMarkWord) {
+ log.info(" Mark word: " PTR_FORMAT, p2i(obj->mark()));
+ }
+ ResourceMark rm;
+ obj->print_on(log.info_stream());
+ _failures = true;
+ }
+ }
+ }
+
+ void do_oop(oop* p) { do_oop_nv(p); }
+ void do_oop(narrowOop* p) { do_oop_nv(p); }
+};
+
+class G1VerifyCodeRootOopClosure: public OopClosure {
+ G1CollectedHeap* _g1h;
+ OopClosure* _root_cl;
+ nmethod* _nm;
+ VerifyOption _vo;
+ bool _failures;
+
+ template <class T> void do_oop_work(T* p) {
+ // First verify that this root is live
+ _root_cl->do_oop(p);
+
+ if (!G1VerifyHeapRegionCodeRoots) {
+ // We're not verifying the code roots attached to heap region.
+ return;
+ }
+
+ // Don't check the code roots during marking verification in a full GC
+ if (_vo == VerifyOption_G1UseMarkWord) {
+ return;
+ }
+
+ // Now verify that the current nmethod (which contains p) is
+ // in the code root list of the heap region containing the
+ // object referenced by p.
+
+ T heap_oop = oopDesc::load_heap_oop(p);
+ if (!oopDesc::is_null(heap_oop)) {
+ oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
+
+ // Now fetch the region containing the object
+ HeapRegion* hr = _g1h->heap_region_containing(obj);
+ HeapRegionRemSet* hrrs = hr->rem_set();
+ // Verify that the strong code root list for this region
+ // contains the nmethod
+ if (!hrrs->strong_code_roots_list_contains(_nm)) {
+ log_info(gc, verify)("Code root location " PTR_FORMAT " "
+ "from nmethod " PTR_FORMAT " not in strong "
+ "code roots for region [" PTR_FORMAT "," PTR_FORMAT ")",
+ p2i(p), p2i(_nm), p2i(hr->bottom()), p2i(hr->end()));
+ _failures = true;
+ }
+ }
+ }
+
+public:
+ G1VerifyCodeRootOopClosure(G1CollectedHeap* g1h, OopClosure* root_cl, VerifyOption vo):
+ _g1h(g1h), _root_cl(root_cl), _vo(vo), _nm(NULL), _failures(false) {}
+
+ void do_oop(oop* p) { do_oop_work(p); }
+ void do_oop(narrowOop* p) { do_oop_work(p); }
+
+ void set_nmethod(nmethod* nm) { _nm = nm; }
+ bool failures() { return _failures; }
+};
+
+class G1VerifyCodeRootBlobClosure: public CodeBlobClosure {
+ G1VerifyCodeRootOopClosure* _oop_cl;
+
+public:
+ G1VerifyCodeRootBlobClosure(G1VerifyCodeRootOopClosure* oop_cl):
+ _oop_cl(oop_cl) {}
+
+ void do_code_blob(CodeBlob* cb) {
+ nmethod* nm = cb->as_nmethod_or_null();
+ if (nm != NULL) {
+ _oop_cl->set_nmethod(nm);
+ nm->oops_do(_oop_cl);
+ }
+ }
+};
+
+class YoungRefCounterClosure : public OopClosure {
+ G1CollectedHeap* _g1h;
+ int _count;
+ public:
+ YoungRefCounterClosure(G1CollectedHeap* g1h) : _g1h(g1h), _count(0) {}
+ void do_oop(oop* p) { if (_g1h->is_in_young(*p)) { _count++; } }
+ void do_oop(narrowOop* p) { ShouldNotReachHere(); }
+
+ int count() { return _count; }
+ void reset_count() { _count = 0; };
+};
+
+class VerifyKlassClosure: public KlassClosure {
+ YoungRefCounterClosure _young_ref_counter_closure;
+ OopClosure *_oop_closure;
+ public:
+ VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {}
+ void do_klass(Klass* k) {
+ k->oops_do(_oop_closure);
+
+ _young_ref_counter_closure.reset_count();
+ k->oops_do(&_young_ref_counter_closure);
+ if (_young_ref_counter_closure.count() > 0) {
+ guarantee(k->has_modified_oops(), "Klass " PTR_FORMAT ", has young refs but is not dirty.", p2i(k));
+ }
+ }
+};
+
+class VerifyLivenessOopClosure: public OopClosure {
+ G1CollectedHeap* _g1h;
+ VerifyOption _vo;
+public:
+ VerifyLivenessOopClosure(G1CollectedHeap* g1h, VerifyOption vo):
+ _g1h(g1h), _vo(vo)
+ { }
+ void do_oop(narrowOop *p) { do_oop_work(p); }
+ void do_oop( oop *p) { do_oop_work(p); }
+
+ template <class T> void do_oop_work(T *p) {
+ oop obj = oopDesc::load_decode_heap_oop(p);
+ guarantee(obj == NULL || !_g1h->is_obj_dead_cond(obj, _vo),
+ "Dead object referenced by a not dead object");
+ }
+};
+
+class VerifyObjsInRegionClosure: public ObjectClosure {
+private:
+ G1CollectedHeap* _g1h;
+ size_t _live_bytes;
+ HeapRegion *_hr;
+ VerifyOption _vo;
+public:
+ // _vo == UsePrevMarking -> use "prev" marking information,
+ // _vo == UseNextMarking -> use "next" marking information,
+ // _vo == UseMarkWord -> use mark word from object header.
+ VerifyObjsInRegionClosure(HeapRegion *hr, VerifyOption vo)
+ : _live_bytes(0), _hr(hr), _vo(vo) {
+ _g1h = G1CollectedHeap::heap();
+ }
+ void do_object(oop o) {
+ VerifyLivenessOopClosure isLive(_g1h, _vo);
+ assert(o != NULL, "Huh?");
+ if (!_g1h->is_obj_dead_cond(o, _vo)) {
+ // If the object is alive according to the mark word,
+ // then verify that the marking information agrees.
+ // Note we can't verify the contra-positive of the
+ // above: if the object is dead (according to the mark
+ // word), it may not be marked, or may have been marked
+ // but has since became dead, or may have been allocated
+ // since the last marking.
+ if (_vo == VerifyOption_G1UseMarkWord) {
+ guarantee(!_g1h->is_obj_dead(o), "mark word and concurrent mark mismatch");
+ }
+
+ o->oop_iterate_no_header(&isLive);
+ if (!_hr->obj_allocated_since_prev_marking(o)) {
+ size_t obj_size = o->size(); // Make sure we don't overflow
+ _live_bytes += (obj_size * HeapWordSize);
+ }
+ }
+ }
+ size_t live_bytes() { return _live_bytes; }
+};
+
+class VerifyArchiveOopClosure: public OopClosure {
+public:
+ VerifyArchiveOopClosure(HeapRegion *hr) { }
+ void do_oop(narrowOop *p) { do_oop_work(p); }
+ void do_oop( oop *p) { do_oop_work(p); }
+
+ template <class T> void do_oop_work(T *p) {
+ oop obj = oopDesc::load_decode_heap_oop(p);
+ guarantee(obj == NULL || G1MarkSweep::in_archive_range(obj),
+ "Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT,
+ p2i(p), p2i(obj));
+ }
+};
+
+class VerifyArchiveRegionClosure: public ObjectClosure {
+public:
+ VerifyArchiveRegionClosure(HeapRegion *hr) { }
+ // Verify that all object pointers are to archive regions.
+ void do_object(oop o) {
+ VerifyArchiveOopClosure checkOop(NULL);
+ assert(o != NULL, "Should not be here for NULL oops");
+ o->oop_iterate_no_header(&checkOop);
+ }
+};
+
+class VerifyRegionClosure: public HeapRegionClosure {
+private:
+ bool _par;
+ VerifyOption _vo;
+ bool _failures;
+public:
+ // _vo == UsePrevMarking -> use "prev" marking information,
+ // _vo == UseNextMarking -> use "next" marking information,
+ // _vo == UseMarkWord -> use mark word from object header.
+ VerifyRegionClosure(bool par, VerifyOption vo)
+ : _par(par),
+ _vo(vo),
+ _failures(false) {}
+
+ bool failures() {
+ return _failures;
+ }
+
+ bool doHeapRegion(HeapRegion* r) {
+ // For archive regions, verify there are no heap pointers to
+ // non-pinned regions. For all others, verify liveness info.
+ if (r->is_archive()) {
+ VerifyArchiveRegionClosure verify_oop_pointers(r);
+ r->object_iterate(&verify_oop_pointers);
+ return true;
+ }
+ if (!r->is_continues_humongous()) {
+ bool failures = false;
+ r->verify(_vo, &failures);
+ if (failures) {
+ _failures = true;
+ } else if (!r->is_starts_humongous()) {
+ VerifyObjsInRegionClosure not_dead_yet_cl(r, _vo);
+ r->object_iterate(¬_dead_yet_cl);
+ if (_vo != VerifyOption_G1UseNextMarking) {
+ if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) {
+ log_info(gc, verify)("[" PTR_FORMAT "," PTR_FORMAT "] max_live_bytes " SIZE_FORMAT " < calculated " SIZE_FORMAT,
+ p2i(r->bottom()), p2i(r->end()), r->max_live_bytes(), not_dead_yet_cl.live_bytes());
+ _failures = true;
+ }
+ } else {
+ // When vo == UseNextMarking we cannot currently do a sanity
+ // check on the live bytes as the calculation has not been
+ // finalized yet.
+ }
+ }
+ }
+ return false; // stop the region iteration if we hit a failure
+ }
+};
+
+// This is the task used for parallel verification of the heap regions
+
+class G1ParVerifyTask: public AbstractGangTask {
+private:
+ G1CollectedHeap* _g1h;
+ VerifyOption _vo;
+ bool _failures;
+ HeapRegionClaimer _hrclaimer;
+
+public:
+ // _vo == UsePrevMarking -> use "prev" marking information,
+ // _vo == UseNextMarking -> use "next" marking information,
+ // _vo == UseMarkWord -> use mark word from object header.
+ G1ParVerifyTask(G1CollectedHeap* g1h, VerifyOption vo) :
+ AbstractGangTask("Parallel verify task"),
+ _g1h(g1h),
+ _vo(vo),
+ _failures(false),
+ _hrclaimer(g1h->workers()->active_workers()) {}
+
+ bool failures() {
+ return _failures;
+ }
+
+ void work(uint worker_id) {
+ HandleMark hm;
+ VerifyRegionClosure blk(true, _vo);
+ _g1h->heap_region_par_iterate(&blk, worker_id, &_hrclaimer);
+ if (blk.failures()) {
+ _failures = true;
+ }
+ }
+};
+
+
+void G1HeapVerifier::verify(VerifyOption vo) {
+ if (!SafepointSynchronize::is_at_safepoint()) {
+ log_info(gc, verify)("Skipping verification. Not at safepoint.");
+ }
+
+ assert(Thread::current()->is_VM_thread(),
+ "Expected to be executed serially by the VM thread at this point");
+
+ log_debug(gc, verify)("Roots");
+ VerifyRootsClosure rootsCl(vo);
+ VerifyKlassClosure klassCl(_g1h, &rootsCl);
+ CLDToKlassAndOopClosure cldCl(&klassCl, &rootsCl, false);
+
+ // We apply the relevant closures to all the oops in the
+ // system dictionary, class loader data graph, the string table
+ // and the nmethods in the code cache.
+ G1VerifyCodeRootOopClosure codeRootsCl(_g1h, &rootsCl, vo);
+ G1VerifyCodeRootBlobClosure blobsCl(&codeRootsCl);
+
+ {
+ G1RootProcessor root_processor(_g1h, 1);
+ root_processor.process_all_roots(&rootsCl,
+ &cldCl,
+ &blobsCl);
+ }
+
+ bool failures = rootsCl.failures() || codeRootsCl.failures();
+
+ if (vo != VerifyOption_G1UseMarkWord) {
+ // If we're verifying during a full GC then the region sets
+ // will have been torn down at the start of the GC. Therefore
+ // verifying the region sets will fail. So we only verify
+ // the region sets when not in a full GC.
+ log_debug(gc, verify)("HeapRegionSets");
+ verify_region_sets();
+ }
+
+ log_debug(gc, verify)("HeapRegions");
+ if (GCParallelVerificationEnabled && ParallelGCThreads > 1) {
+
+ G1ParVerifyTask task(_g1h, vo);
+ _g1h->workers()->run_task(&task);
+ if (task.failures()) {
+ failures = true;
+ }
+
+ } else {
+ VerifyRegionClosure blk(false, vo);
+ _g1h->heap_region_iterate(&blk);
+ if (blk.failures()) {
+ failures = true;
+ }
+ }
+
+ if (G1StringDedup::is_enabled()) {
+ log_debug(gc, verify)("StrDedup");
+ G1StringDedup::verify();
+ }
+
+ if (failures) {
+ log_info(gc, verify)("Heap after failed verification:");
+ // It helps to have the per-region information in the output to
+ // help us track down what went wrong. This is why we call
+ // print_extended_on() instead of print_on().
+ LogHandle(gc, verify) log;
+ ResourceMark rm;
+ _g1h->print_extended_on(log.info_stream());
+ }
+ guarantee(!failures, "there should not have been any failures");
+}
+
+// Heap region set verification
+
+class VerifyRegionListsClosure : public HeapRegionClosure {
+private:
+ HeapRegionSet* _old_set;
+ HeapRegionSet* _humongous_set;
+ HeapRegionManager* _hrm;
+
+public:
+ uint _old_count;
+ uint _humongous_count;
+ uint _free_count;
+
+ VerifyRegionListsClosure(HeapRegionSet* old_set,
+ HeapRegionSet* humongous_set,
+ HeapRegionManager* hrm) :
+ _old_set(old_set), _humongous_set(humongous_set), _hrm(hrm),
+ _old_count(), _humongous_count(), _free_count(){ }
+
+ bool doHeapRegion(HeapRegion* hr) {
+ if (hr->is_young()) {
+ // TODO
+ } else if (hr->is_humongous()) {
+ assert(hr->containing_set() == _humongous_set, "Heap region %u is humongous but not in humongous set.", hr->hrm_index());
+ _humongous_count++;
+ } else if (hr->is_empty()) {
+ assert(_hrm->is_free(hr), "Heap region %u is empty but not on the free list.", hr->hrm_index());
+ _free_count++;
+ } else if (hr->is_old()) {
+ assert(hr->containing_set() == _old_set, "Heap region %u is old but not in the old set.", hr->hrm_index());
+ _old_count++;
+ } else {
+ // There are no other valid region types. Check for one invalid
+ // one we can identify: pinned without old or humongous set.
+ assert(!hr->is_pinned(), "Heap region %u is pinned but not old (archive) or humongous.", hr->hrm_index());
+ ShouldNotReachHere();
+ }
+ return false;
+ }
+
+ void verify_counts(HeapRegionSet* old_set, HeapRegionSet* humongous_set, HeapRegionManager* free_list) {
+ guarantee(old_set->length() == _old_count, "Old set count mismatch. Expected %u, actual %u.", old_set->length(), _old_count);
+ guarantee(humongous_set->length() == _humongous_count, "Hum set count mismatch. Expected %u, actual %u.", humongous_set->length(), _humongous_count);
+ guarantee(free_list->num_free_regions() == _free_count, "Free list count mismatch. Expected %u, actual %u.", free_list->num_free_regions(), _free_count);
+ }
+};
+
+void G1HeapVerifier::verify_region_sets() {
+ assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */);
+
+ // First, check the explicit lists.
+ _g1h->_hrm.verify();
+ {
+ // Given that a concurrent operation might be adding regions to
+ // the secondary free list we have to take the lock before
+ // verifying it.
+ MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag);
+ _g1h->_secondary_free_list.verify_list();
+ }
+
+ // If a concurrent region freeing operation is in progress it will
+ // be difficult to correctly attributed any free regions we come
+ // across to the correct free list given that they might belong to
+ // one of several (free_list, secondary_free_list, any local lists,
+ // etc.). So, if that's the case we will skip the rest of the
+ // verification operation. Alternatively, waiting for the concurrent
+ // operation to complete will have a non-trivial effect on the GC's
+ // operation (no concurrent operation will last longer than the
+ // interval between two calls to verification) and it might hide
+ // any issues that we would like to catch during testing.
+ if (_g1h->free_regions_coming()) {
+ return;
+ }
+
+ // Make sure we append the secondary_free_list on the free_list so
+ // that all free regions we will come across can be safely
+ // attributed to the free_list.
+ _g1h->append_secondary_free_list_if_not_empty_with_lock();
+
+ // Finally, make sure that the region accounting in the lists is
+ // consistent with what we see in the heap.
+
+ VerifyRegionListsClosure cl(&_g1h->_old_set, &_g1h->_humongous_set, &_g1h->_hrm);
+ _g1h->heap_region_iterate(&cl);
+ cl.verify_counts(&_g1h->_old_set, &_g1h->_humongous_set, &_g1h->_hrm);
+}
+
+void G1HeapVerifier::prepare_for_verify() {
+ if (SafepointSynchronize::is_at_safepoint() || ! UseTLAB) {
+ _g1h->ensure_parsability(false);
+ }
+ _g1h->g1_rem_set()->prepare_for_verify();
+}
+
+double G1HeapVerifier::verify(bool guard, const char* msg) {
+ double verify_time_ms = 0.0;
+
+ if (guard && _g1h->total_collections() >= VerifyGCStartAt) {
+ double verify_start = os::elapsedTime();
+ HandleMark hm; // Discard invalid handles created during verification
+ prepare_for_verify();
+ Universe::verify(VerifyOption_G1UsePrevMarking, msg);
+ verify_time_ms = (os::elapsedTime() - verify_start) * 1000;
+ }
+
+ return verify_time_ms;
+}
+
+void G1HeapVerifier::verify_before_gc() {
+ double verify_time_ms = verify(VerifyBeforeGC, "Before GC");
+ _g1h->g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms);
+}
+
+void G1HeapVerifier::verify_after_gc() {
+ double verify_time_ms = verify(VerifyAfterGC, "After GC");
+ _g1h->g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms);
+}
+
+
+#ifndef PRODUCT
+class G1VerifyCardTableCleanup: public HeapRegionClosure {
+ G1HeapVerifier* _verifier;
+ G1SATBCardTableModRefBS* _ct_bs;
+public:
+ G1VerifyCardTableCleanup(G1HeapVerifier* verifier, G1SATBCardTableModRefBS* ct_bs)
+ : _verifier(verifier), _ct_bs(ct_bs) { }
+ virtual bool doHeapRegion(HeapRegion* r) {
+ if (r->is_survivor()) {
+ _verifier->verify_dirty_region(r);
+ } else {
+ _verifier->verify_not_dirty_region(r);
+ }
+ return false;
+ }
+};
+
+void G1HeapVerifier::verify_card_table_cleanup() {
+ if (G1VerifyCTCleanup || VerifyAfterGC) {
+ G1VerifyCardTableCleanup cleanup_verifier(this, _g1h->g1_barrier_set());
+ _g1h->heap_region_iterate(&cleanup_verifier);
+ }
+}
+
+void G1HeapVerifier::verify_not_dirty_region(HeapRegion* hr) {
+ // All of the region should be clean.
+ G1SATBCardTableModRefBS* ct_bs = _g1h->g1_barrier_set();
+ MemRegion mr(hr->bottom(), hr->end());
+ ct_bs->verify_not_dirty_region(mr);
+}
+
+void G1HeapVerifier::verify_dirty_region(HeapRegion* hr) {
+ // We cannot guarantee that [bottom(),end()] is dirty. Threads
+ // dirty allocated blocks as they allocate them. The thread that
+ // retires each region and replaces it with a new one will do a
+ // maximal allocation to fill in [pre_dummy_top(),end()] but will
+ // not dirty that area (one less thing to have to do while holding
+ // a lock). So we can only verify that [bottom(),pre_dummy_top()]
+ // is dirty.
+ G1SATBCardTableModRefBS* ct_bs = _g1h->g1_barrier_set();
+ MemRegion mr(hr->bottom(), hr->pre_dummy_top());
+ if (hr->is_young()) {
+ ct_bs->verify_g1_young_region(mr);
+ } else {
+ ct_bs->verify_dirty_region(mr);
+ }
+}
+
+void G1HeapVerifier::verify_dirty_young_list(HeapRegion* head) {
+ G1SATBCardTableModRefBS* ct_bs = _g1h->g1_barrier_set();
+ for (HeapRegion* hr = head; hr != NULL; hr = hr->get_next_young_region()) {
+ verify_dirty_region(hr);
+ }
+}
+
+void G1HeapVerifier::verify_dirty_young_regions() {
+ verify_dirty_young_list(_g1h->young_list()->first_region());
+}
+
+bool G1HeapVerifier::verify_no_bits_over_tams(const char* bitmap_name, G1CMBitMapRO* bitmap,
+ HeapWord* tams, HeapWord* end) {
+ guarantee(tams <= end,
+ "tams: " PTR_FORMAT " end: " PTR_FORMAT, p2i(tams), p2i(end));
+ HeapWord* result = bitmap->getNextMarkedWordAddress(tams, end);
+ if (result < end) {
+ log_info(gc, verify)("## wrong marked address on %s bitmap: " PTR_FORMAT, bitmap_name, p2i(result));
+ log_info(gc, verify)("## %s tams: " PTR_FORMAT " end: " PTR_FORMAT, bitmap_name, p2i(tams), p2i(end));
+ return false;
+ }
+ return true;
+}
+
+bool G1HeapVerifier::verify_bitmaps(const char* caller, HeapRegion* hr) {
+ G1CMBitMapRO* prev_bitmap = _g1h->concurrent_mark()->prevMarkBitMap();
+ G1CMBitMapRO* next_bitmap = (G1CMBitMapRO*) _g1h->concurrent_mark()->nextMarkBitMap();
+
+ HeapWord* bottom = hr->bottom();
+ HeapWord* ptams = hr->prev_top_at_mark_start();
+ HeapWord* ntams = hr->next_top_at_mark_start();
+ HeapWord* end = hr->end();
+
+ bool res_p = verify_no_bits_over_tams("prev", prev_bitmap, ptams, end);
+
+ bool res_n = true;
+ // We reset mark_in_progress() before we reset _cmThread->in_progress() and in this window
+ // we do the clearing of the next bitmap concurrently. Thus, we can not verify the bitmap
+ // if we happen to be in that state.
+ if (_g1h->collector_state()->mark_in_progress() || !_g1h->_cmThread->in_progress()) {
+ res_n = verify_no_bits_over_tams("next", next_bitmap, ntams, end);
+ }
+ if (!res_p || !res_n) {
+ log_info(gc, verify)("#### Bitmap verification failed for " HR_FORMAT, HR_FORMAT_PARAMS(hr));
+ log_info(gc, verify)("#### Caller: %s", caller);
+ return false;
+ }
+ return true;
+}
+
+void G1HeapVerifier::check_bitmaps(const char* caller, HeapRegion* hr) {
+ if (!G1VerifyBitmaps) return;
+
+ guarantee(verify_bitmaps(caller, hr), "bitmap verification");
+}
+
+class G1VerifyBitmapClosure : public HeapRegionClosure {
+private:
+ const char* _caller;
+ G1HeapVerifier* _verifier;
+ bool _failures;
+
+public:
+ G1VerifyBitmapClosure(const char* caller, G1HeapVerifier* verifier) :
+ _caller(caller), _verifier(verifier), _failures(false) { }
+
+ bool failures() { return _failures; }
+
+ virtual bool doHeapRegion(HeapRegion* hr) {
+ bool result = _verifier->verify_bitmaps(_caller, hr);
+ if (!result) {
+ _failures = true;
+ }
+ return false;
+ }
+};
+
+void G1HeapVerifier::check_bitmaps(const char* caller) {
+ if (!G1VerifyBitmaps) return;
+
+ G1VerifyBitmapClosure cl(caller, this);
+ _g1h->heap_region_iterate(&cl);
+ guarantee(!cl.failures(), "bitmap verification");
+}
+
+class G1CheckCSetFastTableClosure : public HeapRegionClosure {
+ private:
+ bool _failures;
+ public:
+ G1CheckCSetFastTableClosure() : HeapRegionClosure(), _failures(false) { }
+
+ virtual bool doHeapRegion(HeapRegion* hr) {
+ uint i = hr->hrm_index();
+ InCSetState cset_state = (InCSetState) G1CollectedHeap::heap()->_in_cset_fast_test.get_by_index(i);
+ if (hr->is_humongous()) {
+ if (hr->in_collection_set()) {
+ log_info(gc, verify)("## humongous region %u in CSet", i);
+ _failures = true;
+ return true;
+ }
+ if (cset_state.is_in_cset()) {
+ log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i);
+ _failures = true;
+ return true;
+ }
+ if (hr->is_continues_humongous() && cset_state.is_humongous()) {
+ log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i);
+ _failures = true;
+ return true;
+ }
+ } else {
+ if (cset_state.is_humongous()) {
+ log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i);
+ _failures = true;
+ return true;
+ }
+ if (hr->in_collection_set() != cset_state.is_in_cset()) {
+ log_info(gc, verify)("## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
+ hr->in_collection_set(), cset_state.value(), i);
+ _failures = true;
+ return true;
+ }
+ if (cset_state.is_in_cset()) {
+ if (hr->is_young() != (cset_state.is_young())) {
+ log_info(gc, verify)("## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
+ hr->is_young(), cset_state.value(), i);
+ _failures = true;
+ return true;
+ }
+ if (hr->is_old() != (cset_state.is_old())) {
+ log_info(gc, verify)("## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
+ hr->is_old(), cset_state.value(), i);
+ _failures = true;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool failures() const { return _failures; }
+};
+
+bool G1HeapVerifier::check_cset_fast_test() {
+ G1CheckCSetFastTableClosure cl;
+ _g1h->_hrm.iterate(&cl);
+ return !cl.failures();
+}
+#endif // PRODUCT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1HEAPVERIFIER_HPP
+#define SHARE_VM_GC_G1_G1HEAPVERIFIER_HPP
+
+#include "gc/g1/heapRegionSet.hpp"
+#include "memory/allocation.hpp"
+#include "memory/universe.hpp"
+
+class G1CollectedHeap;
+
+class G1HeapVerifier : public CHeapObj<mtGC> {
+private:
+ G1CollectedHeap* _g1h;
+
+ // verify_region_sets() performs verification over the region
+ // lists. It will be compiled in the product code to be used when
+ // necessary (i.e., during heap verification).
+ void verify_region_sets();
+
+public:
+
+ G1HeapVerifier(G1CollectedHeap* heap) : _g1h(heap) { }
+
+ // Perform verification.
+
+ // vo == UsePrevMarking -> use "prev" marking information,
+ // vo == UseNextMarking -> use "next" marking information
+ // vo == UseMarkWord -> use the mark word in the object header
+ //
+ // NOTE: Only the "prev" marking information is guaranteed to be
+ // consistent most of the time, so most calls to this should use
+ // vo == UsePrevMarking.
+ // Currently, there is only one case where this is called with
+ // vo == UseNextMarking, which is to verify the "next" marking
+ // information at the end of remark.
+ // Currently there is only one place where this is called with
+ // vo == UseMarkWord, which is to verify the marking during a
+ // full GC.
+ void verify(VerifyOption vo);
+
+ // verify_region_sets_optional() is planted in the code for
+ // list verification in non-product builds (and it can be enabled in
+ // product builds by defining HEAP_REGION_SET_FORCE_VERIFY to be 1).
+#if HEAP_REGION_SET_FORCE_VERIFY
+ void verify_region_sets_optional() {
+ verify_region_sets();
+ }
+#else // HEAP_REGION_SET_FORCE_VERIFY
+ void verify_region_sets_optional() { }
+#endif // HEAP_REGION_SET_FORCE_VERIFY
+
+ void prepare_for_verify();
+ double verify(bool guard, const char* msg);
+ void verify_before_gc();
+ void verify_after_gc();
+
+#ifndef PRODUCT
+ // Make sure that the given bitmap has no marked objects in the
+ // range [from,limit). If it does, print an error message and return
+ // false. Otherwise, just return true. bitmap_name should be "prev"
+ // or "next".
+ bool verify_no_bits_over_tams(const char* bitmap_name, G1CMBitMapRO* bitmap,
+ HeapWord* from, HeapWord* limit);
+
+ // Verify that the prev / next bitmap range [tams,end) for the given
+ // region has no marks. Return true if all is well, false if errors
+ // are detected.
+ bool verify_bitmaps(const char* caller, HeapRegion* hr);
+#endif // PRODUCT
+
+ // If G1VerifyBitmaps is set, verify that the marking bitmaps for
+ // the given region do not have any spurious marks. If errors are
+ // detected, print appropriate error messages and crash.
+ void check_bitmaps(const char* caller, HeapRegion* hr) PRODUCT_RETURN;
+
+ // If G1VerifyBitmaps is set, verify that the marking bitmaps do not
+ // have any spurious marks. If errors are detected, print
+ // appropriate error messages and crash.
+ void check_bitmaps(const char* caller) PRODUCT_RETURN;
+
+ // Do sanity check on the contents of the in-cset fast test table.
+ bool check_cset_fast_test() PRODUCT_RETURN_( return true; );
+
+ void verify_card_table_cleanup() PRODUCT_RETURN;
+
+ void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
+ void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
+ void verify_dirty_young_list(HeapRegion* head) PRODUCT_RETURN;
+ void verify_dirty_young_regions() PRODUCT_RETURN;
+};
+
+#endif // SHARE_VM_GC_G1_G1HEAPVERIFIER_HPP
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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,12 +31,12 @@
class HeapRegion;
class G1CollectedHeap;
class G1RemSet;
-class ConcurrentMark;
+class G1ConcurrentMark;
class DirtyCardToOopClosure;
-class CMBitMap;
-class CMMarkStack;
+class G1CMBitMap;
+class G1CMMarkStack;
class G1ParScanThreadState;
-class CMTask;
+class G1CMTask;
class ReferenceProcessor;
// A class that scans oops in a given heap region (much as OopsInGenClosure
@@ -92,7 +92,7 @@
G1ParScanThreadState* _par_scan_state;
uint _worker_id; // Cache value from par_scan_state.
Klass* _scanned_klass;
- ConcurrentMark* _cm;
+ G1ConcurrentMark* _cm;
// Mark the object if it's not already marked. This is used to mark
// objects pointed to by roots that are guaranteed not to move
@@ -170,12 +170,12 @@
// Closure for iterating over object fields during concurrent marking
class G1CMOopClosure : public MetadataAwareOopClosure {
protected:
- ConcurrentMark* _cm;
+ G1ConcurrentMark* _cm;
private:
G1CollectedHeap* _g1h;
- CMTask* _task;
+ G1CMTask* _task;
public:
- G1CMOopClosure(G1CollectedHeap* g1h, ConcurrentMark* cm, CMTask* task);
+ G1CMOopClosure(G1CollectedHeap* g1h, G1ConcurrentMark* cm, G1CMTask* task);
template <class T> void do_oop_nv(T* p);
virtual void do_oop( oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
@@ -185,10 +185,10 @@
class G1RootRegionScanClosure : public MetadataAwareOopClosure {
private:
G1CollectedHeap* _g1h;
- ConcurrentMark* _cm;
+ G1ConcurrentMark* _cm;
uint _worker_id;
public:
- G1RootRegionScanClosure(G1CollectedHeap* g1h, ConcurrentMark* cm,
+ G1RootRegionScanClosure(G1CollectedHeap* g1h, G1ConcurrentMark* cm,
uint worker_id) :
_g1h(g1h), _cm(cm), _worker_id(worker_id) { }
template <class T> void do_oop_nv(T* p);
@@ -206,9 +206,9 @@
OopClosure* _c2;
public:
G1Mux2Closure(OopClosure *c1, OopClosure *c2);
- template <class T> void do_oop_work(T* p);
- virtual void do_oop(oop* p) { do_oop_work(p); }
- virtual void do_oop(narrowOop* p) { do_oop_work(p); }
+ template <class T> inline void do_oop_work(T* p);
+ virtual inline void do_oop(oop* p);
+ virtual inline void do_oop(narrowOop* p);
};
// A closure that returns true if it is actually applied
@@ -219,9 +219,9 @@
public:
G1TriggerClosure();
bool triggered() const { return _triggered; }
- template <class T> void do_oop_work(T* p);
- virtual void do_oop(oop* p) { do_oop_work(p); }
- virtual void do_oop(narrowOop* p) { do_oop_work(p); }
+ template <class T> inline void do_oop_work(T* p);
+ virtual inline void do_oop(oop* p);
+ virtual inline void do_oop(narrowOop* p);
};
// A closure which uses a triggering closure to determine
@@ -232,9 +232,9 @@
OopClosure* _oop_cl;
public:
G1InvokeIfNotTriggeredClosure(G1TriggerClosure* t, OopClosure* oc);
- template <class T> void do_oop_work(T* p);
- virtual void do_oop(oop* p) { do_oop_work(p); }
- virtual void do_oop(narrowOop* p) { do_oop_work(p); }
+ template <class T> inline void do_oop_work(T* p);
+ virtual inline void do_oop(oop* p);
+ virtual inline void do_oop(narrowOop* p);
};
class G1UpdateRSOrPushRefOopClosure: public OopClosure {
@@ -263,9 +263,9 @@
return result;
}
- template <class T> void do_oop_work(T* p);
- virtual void do_oop(narrowOop* p) { do_oop_work(p); }
- virtual void do_oop(oop* p) { do_oop_work(p); }
+ template <class T> inline void do_oop_work(T* p);
+ virtual inline void do_oop(narrowOop* p);
+ virtual inline void do_oop(oop* p);
};
#endif // SHARE_VM_GC_G1_G1OOPCLOSURES_HPP
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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,8 +25,8 @@
#ifndef SHARE_VM_GC_G1_G1OOPCLOSURES_INLINE_HPP
#define SHARE_VM_GC_G1_G1OOPCLOSURES_INLINE_HPP
-#include "gc/g1/concurrentMark.inline.hpp"
#include "gc/g1/g1CollectedHeap.hpp"
+#include "gc/g1/g1ConcurrentMark.inline.hpp"
#include "gc/g1/g1OopClosures.hpp"
#include "gc/g1/g1ParScanThreadState.inline.hpp"
#include "gc/g1/g1RemSet.hpp"
@@ -141,12 +141,16 @@
_c1->do_oop(p);
_c2->do_oop(p);
}
+void G1Mux2Closure::do_oop(oop* p) { do_oop_work(p); }
+void G1Mux2Closure::do_oop(narrowOop* p) { do_oop_work(p); }
template <class T>
inline void G1TriggerClosure::do_oop_work(T* p) {
// Record that this closure was actually applied (triggered).
_triggered = true;
}
+void G1TriggerClosure::do_oop(oop* p) { do_oop_work(p); }
+void G1TriggerClosure::do_oop(narrowOop* p) { do_oop_work(p); }
template <class T>
inline void G1InvokeIfNotTriggeredClosure::do_oop_work(T* p) {
@@ -154,6 +158,8 @@
_oop_cl->do_oop(p);
}
}
+void G1InvokeIfNotTriggeredClosure::do_oop(oop* p) { do_oop_work(p); }
+void G1InvokeIfNotTriggeredClosure::do_oop(narrowOop* p) { do_oop_work(p); }
template <class T>
inline void G1UpdateRSOrPushRefOopClosure::do_oop_work(T* p) {
@@ -224,6 +230,8 @@
to->rem_set()->add_reference(p, _worker_i);
}
}
+void G1UpdateRSOrPushRefOopClosure::do_oop(oop* p) { do_oop_work(p); }
+void G1UpdateRSOrPushRefOopClosure::do_oop(narrowOop* p) { do_oop_work(p); }
template <class T>
void G1ParCopyHelper::do_klass_barrier(T* p, oop new_obj) {
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -34,6 +34,7 @@
#include "gc/g1/g1HotCardCache.hpp"
#include "gc/g1/g1OopClosures.inline.hpp"
#include "gc/g1/g1RemSet.inline.hpp"
+#include "gc/g1/g1SATBCardTableModRefBS.inline.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionManager.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
--- a/hotspot/src/share/vm/gc/g1/g1RemSetSummary.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1RemSetSummary.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -221,7 +221,7 @@
class HRRSStatsIter: public HeapRegionClosure {
private:
RegionTypeCounter _young;
- RegionTypeCounter _humonguous;
+ RegionTypeCounter _humongous;
RegionTypeCounter _free;
RegionTypeCounter _old;
RegionTypeCounter _all;
@@ -245,7 +245,7 @@
HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; }
public:
- HRRSStatsIter() : _all("All"), _young("Young"), _humonguous("Humonguous"),
+ HRRSStatsIter() : _all("All"), _young("Young"), _humongous("Humongous"),
_free("Free"), _old("Old"), _max_code_root_mem_sz_region(NULL), _max_rs_mem_sz_region(NULL),
_max_rs_mem_sz(0), _max_code_root_mem_sz(0)
{}
@@ -274,7 +274,7 @@
} else if (r->is_young()) {
current = &_young;
} else if (r->is_humongous()) {
- current = &_humonguous;
+ current = &_humongous;
} else if (r->is_old()) {
current = &_old;
} else {
@@ -287,7 +287,7 @@
}
void print_summary_on(outputStream* out) {
- RegionTypeCounter* counters[] = { &_young, &_humonguous, &_free, &_old, NULL };
+ RegionTypeCounter* counters[] = { &_young, &_humongous, &_free, &_old, NULL };
out->print_cr(" Current rem set statistics");
out->print_cr(" Total per region rem sets sizes = " SIZE_FORMAT "K."
--- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#include "gc/g1/g1SATBCardTableModRefBS.inline.hpp"
#include "gc/g1/heapRegion.hpp"
#include "gc/g1/satbMarkQueue.hpp"
#include "gc/shared/memset_with_concurrent_readers.hpp"
--- a/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -58,20 +58,11 @@
// We export this to make it available in cases where the static
// type of the barrier set is known. Note that it is non-virtual.
- template <class T> inline void inline_write_ref_field_pre(T* field, oop newVal) {
- T heap_oop = oopDesc::load_heap_oop(field);
- if (!oopDesc::is_null(heap_oop)) {
- enqueue(oopDesc::decode_heap_oop(heap_oop));
- }
- }
+ template <class T> inline void inline_write_ref_field_pre(T* field, oop newVal);
// These are the more general virtual versions.
- virtual void write_ref_field_pre_work(oop* field, oop new_val) {
- inline_write_ref_field_pre(field, new_val);
- }
- virtual void write_ref_field_pre_work(narrowOop* field, oop new_val) {
- inline_write_ref_field_pre(field, new_val);
- }
+ inline virtual void write_ref_field_pre_work(oop* field, oop new_val);
+ inline virtual void write_ref_field_pre_work(narrowOop* field, oop new_val);
virtual void write_ref_field_pre_work(void* field, oop new_val) {
guarantee(false, "Not needed");
}
@@ -98,15 +89,7 @@
return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val();
}
- void set_card_claimed(size_t card_index) {
- jbyte val = _byte_map[card_index];
- if (val == clean_card_val()) {
- val = (jbyte)claimed_card_val();
- } else {
- val |= (jbyte)claimed_card_val();
- }
- _byte_map[card_index] = val;
- }
+ inline void set_card_claimed(size_t card_index);
void verify_g1_young_region(MemRegion mr) PRODUCT_RETURN;
void g1_mark_as_young(const MemRegion& mr);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1SATBCardTableModRefBS.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1SATBCARDTABLEMODREFBS_INLINE_HPP
+#define SHARE_VM_GC_G1_G1SATBCARDTABLEMODREFBS_INLINE_HPP
+
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#include "oops/oop.inline.hpp"
+
+// We export this to make it available in cases where the static
+// type of the barrier set is known. Note that it is non-virtual.
+template <class T> void G1SATBCardTableModRefBS::inline_write_ref_field_pre(T* field, oop newVal) {
+ T heap_oop = oopDesc::load_heap_oop(field);
+ if (!oopDesc::is_null(heap_oop)) {
+ enqueue(oopDesc::decode_heap_oop(heap_oop));
+ }
+}
+
+// These are the more general virtual versions.
+void G1SATBCardTableModRefBS::write_ref_field_pre_work(oop* field, oop new_val) {
+ inline_write_ref_field_pre(field, new_val);
+}
+void G1SATBCardTableModRefBS::write_ref_field_pre_work(narrowOop* field, oop new_val) {
+ inline_write_ref_field_pre(field, new_val);
+}
+
+void G1SATBCardTableModRefBS::set_card_claimed(size_t card_index) {
+ jbyte val = _byte_map[card_index];
+ if (val == clean_card_val()) {
+ val = (jbyte)claimed_card_val();
+ } else {
+ val |= (jbyte)claimed_card_val();
+ }
+ _byte_map[card_index] = val;
+}
+
+#endif // SHARE_VM_GC_G1_G1SATBCARDTABLEMODREFBS_INLINE_HPP
--- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -61,9 +61,8 @@
true,
Monitor::_safepoint_check_never);
+ set_name("G1 Young RemSet Sampling");
create_and_start();
-
- set_name("G1 Young RemSet Sampling");
}
void G1YoungRemSetSamplingThread::sleep_before_next_cycle() {
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -143,6 +143,7 @@
// The cast to int is safe, given that we've bounded region_size by
// MIN_REGION_SIZE and MAX_REGION_SIZE.
GrainBytes = region_size;
+ log_info(gc, heap)("Heap region size: " SIZE_FORMAT "M", GrainBytes / M);
guarantee(GrainWords == 0, "we should only set it once");
GrainWords = GrainBytes >> LogHeapWordSize;
--- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -110,7 +110,9 @@
public:
- HeapRegion* hr() const { return _hr; }
+ HeapRegion* hr() const {
+ return (HeapRegion*) OrderAccess::load_ptr_acquire(&_hr);
+ }
jint occupied() const {
// Overkill, but if we ever need it...
@@ -123,10 +125,12 @@
set_next(NULL);
set_prev(NULL);
}
- _hr = hr;
_collision_list_next = NULL;
_occupied = 0;
_bm.clear();
+ // Make sure that the bitmap clearing above has been finished before publishing
+ // this PRT to concurrent threads.
+ OrderAccess::release_store_ptr(&_hr, hr);
}
void add_reference(OopOrNarrowOopStar from) {
@@ -357,7 +361,7 @@
int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift);
if (G1FromCardCache::contains_or_replace(tid, cur_hrm_ind, from_card)) {
- assert(contains_reference(from), "We just added it!");
+ assert(contains_reference(from), "We just found " PTR_FORMAT " in the FromCardCache", p2i(from));
return;
}
@@ -367,7 +371,7 @@
// If the region is already coarsened, return.
if (_coarse_map.at(from_hrm_ind)) {
- assert(contains_reference(from), "We just added it!");
+ assert(contains_reference(from), "We just found " PTR_FORMAT " in the Coarse table", p2i(from));
return;
}
@@ -388,7 +392,7 @@
"Must be in range.");
if (G1HRRSUseSparseTable &&
_sparse_table.add_card(from_hrm_ind, card_index)) {
- assert(contains_reference_locked(from), "We just added it!");
+ assert(contains_reference_locked(from), "We just added " PTR_FORMAT " to the Sparse table", p2i(from));
return;
}
@@ -438,7 +442,7 @@
assert(prt != NULL, "Inv");
prt->add_reference(from);
- assert(contains_reference(from), "We just added it!");
+ assert(contains_reference(from), "We just added " PTR_FORMAT " to the PRT", p2i(from));
}
PerRegionTable*
@@ -785,6 +789,9 @@
void HeapRegionRemSet::add_strong_code_root(nmethod* nm) {
assert(nm != NULL, "sanity");
+ assert((!CodeCache_lock->owned_by_self() || SafepointSynchronize::is_at_safepoint()),
+ "should call add_strong_code_root_locked instead. CodeCache_lock->owned_by_self(): %s, is_at_safepoint(): %s",
+ BOOL_TO_STR(CodeCache_lock->owned_by_self()), BOOL_TO_STR(SafepointSynchronize::is_at_safepoint()));
// Optimistic unlocked contains-check
if (!_code_roots.contains(nm)) {
MutexLockerEx ml(&_m, Mutex::_no_safepoint_check_flag);
@@ -794,6 +801,12 @@
void HeapRegionRemSet::add_strong_code_root_locked(nmethod* nm) {
assert(nm != NULL, "sanity");
+ assert((CodeCache_lock->owned_by_self() ||
+ (SafepointSynchronize::is_at_safepoint() &&
+ (_m.owned_by_self() || Thread::current()->is_VM_thread()))),
+ "not safely locked. CodeCache_lock->owned_by_self(): %s, is_at_safepoint(): %s, _m.owned_by_self(): %s, Thread::current()->is_VM_thread(): %s",
+ BOOL_TO_STR(CodeCache_lock->owned_by_self()), BOOL_TO_STR(SafepointSynchronize::is_at_safepoint()),
+ BOOL_TO_STR(_m.owned_by_self()), BOOL_TO_STR(Thread::current()->is_VM_thread()));
_code_roots.add(nm);
}
--- a/hotspot/src/share/vm/gc/parallel/asPSYoungGen.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/asPSYoungGen.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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,7 +26,7 @@
#include "gc/parallel/asPSYoungGen.hpp"
#include "gc/parallel/parallelScavengeHeap.hpp"
#include "gc/parallel/psMarkSweepDecorator.hpp"
-#include "gc/parallel/psScavenge.hpp"
+#include "gc/parallel/psScavenge.inline.hpp"
#include "gc/parallel/psYoungGen.hpp"
#include "gc/shared/gcUtil.hpp"
#include "gc/shared/spaceDecorator.hpp"
--- a/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/cardTableExtension.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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,6 +25,7 @@
#include "precompiled.hpp"
#include "gc/parallel/cardTableExtension.hpp"
#include "gc/parallel/gcTaskManager.hpp"
+#include "gc/parallel/objectStartArray.inline.hpp"
#include "gc/parallel/parallelScavengeHeap.hpp"
#include "gc/parallel/psPromotionManager.inline.hpp"
#include "gc/parallel/psScavenge.hpp"
--- a/hotspot/src/share/vm/gc/parallel/objectStartArray.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/objectStartArray.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "gc/parallel/objectStartArray.hpp"
+#include "gc/parallel/objectStartArray.inline.hpp"
#include "gc/shared/cardTableModRefBS.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/oop.inline.hpp"
@@ -123,7 +123,6 @@
memset(_blocks_region.start(), clean_block, _blocks_region.byte_size());
}
-
bool ObjectStartArray::object_starts_in_range(HeapWord* start_addr,
HeapWord* end_addr) const {
assert(start_addr <= end_addr,
--- a/hotspot/src/share/vm/gc/parallel/objectStartArray.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/objectStartArray.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -139,23 +139,7 @@
// a given block. The blocks contain the offset of the last
// object in that block. Scroll backwards by one, and the first
// object hit should be at the beginning of the block
- HeapWord* object_start(HeapWord* addr) const {
- assert_covered_region_contains(addr);
- jbyte* block = block_for_addr(addr);
- HeapWord* scroll_forward = offset_addr_for_block(block--);
- while (scroll_forward > addr) {
- scroll_forward = offset_addr_for_block(block--);
- }
-
- HeapWord* next = scroll_forward;
- while (next <= addr) {
- scroll_forward = next;
- next += oop(next)->size();
- }
- assert(scroll_forward <= addr, "wrong order for current and arg");
- assert(addr <= next, "wrong order for arg and next");
- return scroll_forward;
- }
+ inline HeapWord* object_start(HeapWord* addr) const;
bool is_block_allocated(HeapWord* addr) {
assert_covered_region_contains(addr);
@@ -165,7 +149,6 @@
return true;
}
-#undef assert_covered_region_contains
// Return true if an object starts in the range of heap addresses.
// If an object starts at an address corresponding to
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/parallel/objectStartArray.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_PARALLEL_OBJECTSTARTARRAY_INLINE_HPP
+#define SHARE_VM_GC_PARALLEL_OBJECTSTARTARRAY_INLINE_HPP
+
+#include "gc/parallel/objectStartArray.hpp"
+
+// Optimized for finding the first object that crosses into
+// a given block. The blocks contain the offset of the last
+// object in that block. Scroll backwards by one, and the first
+// object hit should be at the beginning of the block
+HeapWord* ObjectStartArray::object_start(HeapWord* addr) const {
+ assert_covered_region_contains(addr);
+ jbyte* block = block_for_addr(addr);
+ HeapWord* scroll_forward = offset_addr_for_block(block--);
+ while (scroll_forward > addr) {
+ scroll_forward = offset_addr_for_block(block--);
+ }
+
+ HeapWord* next = scroll_forward;
+ while (next <= addr) {
+ scroll_forward = next;
+ next += oop(next)->size();
+ }
+ assert(scroll_forward <= addr, "wrong order for current and arg");
+ assert(addr <= next, "wrong order for arg and next");
+ return scroll_forward;
+}
+
+
+#endif // SHARE_VM_GC_PARALLEL_OBJECTSTARTARRAY_INLINE_HPP
--- a/hotspot/src/share/vm/gc/parallel/parMarkBitMap.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/parMarkBitMap.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -24,7 +24,8 @@
#include "precompiled.hpp"
#include "gc/parallel/parMarkBitMap.hpp"
-#include "gc/parallel/psParallelCompact.hpp"
+#include "gc/parallel/psCompactionManager.inline.hpp"
+#include "gc/parallel/psParallelCompact.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomic.inline.hpp"
#include "runtime/os.hpp"
@@ -96,7 +97,20 @@
return false;
}
-size_t ParMarkBitMap::live_words_in_range(HeapWord* beg_addr, oop end_obj) const
+inline bool
+ParMarkBitMap::is_live_words_in_range_in_cache(ParCompactionManager* cm, HeapWord* beg_addr) const {
+ return cm->last_query_begin() == beg_addr;
+}
+
+inline void
+ParMarkBitMap::update_live_words_in_range_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj, size_t result) const {
+ cm->set_last_query_begin(beg_addr);
+ cm->set_last_query_object(end_obj);
+ cm->set_last_query_return(result);
+}
+
+size_t
+ParMarkBitMap::live_words_in_range_helper(HeapWord* beg_addr, oop end_obj) const
{
assert(beg_addr <= (HeapWord*)end_obj, "bad range");
assert(is_marked(end_obj), "end_obj must be live");
@@ -117,6 +131,42 @@
return bits_to_words(live_bits);
}
+size_t
+ParMarkBitMap::live_words_in_range_use_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj) const
+{
+ HeapWord* last_beg = cm->last_query_begin();
+ oop last_obj = cm->last_query_object();
+ size_t last_ret = cm->last_query_return();
+ if (end_obj > last_obj) {
+ last_ret = last_ret + live_words_in_range_helper((HeapWord*)last_obj, end_obj);
+ last_obj = end_obj;
+ } else if (end_obj < last_obj) {
+ // The cached value is for an object that is to the left (lower address) of the current
+ // end_obj. Calculate back from that cached value.
+ if (pointer_delta((HeapWord*)end_obj, (HeapWord*)beg_addr) > pointer_delta((HeapWord*)last_obj, (HeapWord*)end_obj)) {
+ last_ret = last_ret - live_words_in_range_helper((HeapWord*)end_obj, last_obj);
+ } else {
+ last_ret = live_words_in_range_helper(beg_addr, end_obj);
+ }
+ last_obj = end_obj;
+ }
+
+ update_live_words_in_range_cache(cm, last_beg, last_obj, last_ret);
+ return last_ret;
+}
+
+size_t
+ParMarkBitMap::live_words_in_range(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj) const
+{
+ // Try to reuse result from ParCompactionManager cache first.
+ if (is_live_words_in_range_in_cache(cm, beg_addr)) {
+ return live_words_in_range_use_cache(cm, beg_addr, end_obj);
+ }
+ size_t ret = live_words_in_range_helper(beg_addr, end_obj);
+ update_live_words_in_range_cache(cm, beg_addr, end_obj, ret);
+ return ret;
+}
+
ParMarkBitMap::IterationStatus
ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure,
idx_t range_beg, idx_t range_end) const
--- a/hotspot/src/share/vm/gc/parallel/parMarkBitMap.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/parMarkBitMap.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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,6 +31,7 @@
class ParMarkBitMapClosure;
class PSVirtualSpace;
+class ParCompactionManager;
class ParMarkBitMap: public CHeapObj<mtGC>
{
@@ -124,7 +125,7 @@
// the range are included in the result. The end of the range must be a live object,
// which is the case when updating pointers. This allows a branch to be removed
// from inside the loop.
- size_t live_words_in_range(HeapWord* beg_addr, oop end_obj) const;
+ size_t live_words_in_range(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj) const;
inline HeapWord* region_start() const;
inline HeapWord* region_end() const;
@@ -167,6 +168,12 @@
#endif // #ifdef ASSERT
private:
+ size_t live_words_in_range_helper(HeapWord* beg_addr, oop end_obj) const;
+
+ bool is_live_words_in_range_in_cache(ParCompactionManager* cm, HeapWord* beg_addr) const;
+ size_t live_words_in_range_use_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj) const;
+ void update_live_words_in_range_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj, size_t result) const;
+
// Each bit in the bitmap represents one unit of 'object granularity.' Objects
// are double-word aligned in 32-bit VMs, but not in 64-bit VMs, so the 32-bit
// granularity is 2, 64-bit is 1.
--- a/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/parallelScavengeHeap.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -28,10 +28,11 @@
#include "gc/parallel/cardTableExtension.hpp"
#include "gc/parallel/gcTaskManager.hpp"
#include "gc/parallel/generationSizer.hpp"
+#include "gc/parallel/objectStartArray.inline.hpp"
#include "gc/parallel/parallelScavengeHeap.inline.hpp"
#include "gc/parallel/psAdaptiveSizePolicy.hpp"
#include "gc/parallel/psMarkSweep.hpp"
-#include "gc/parallel/psParallelCompact.hpp"
+#include "gc/parallel/psParallelCompact.inline.hpp"
#include "gc/parallel/psPromotionManager.hpp"
#include "gc/parallel/psScavenge.hpp"
#include "gc/parallel/vmPSOperations.hpp"
--- a/hotspot/src/share/vm/gc/parallel/psCompactionManager.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psCompactionManager.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -68,6 +68,8 @@
marking_stack()->initialize();
_objarray_stack.initialize();
+
+ reset_bitmap_query_cache();
}
ParCompactionManager::~ParCompactionManager() {
@@ -124,6 +126,13 @@
"Not initialized?");
}
+void ParCompactionManager::reset_all_bitmap_query_caches() {
+ uint parallel_gc_threads = PSParallelCompact::gc_task_manager()->workers();
+ for (uint i=0; i<=parallel_gc_threads; i++) {
+ _manager_array[i]->reset_bitmap_query_cache();
+ }
+}
+
int ParCompactionManager::pop_recycled_stack_index() {
assert(_recycled_bottom <= _recycled_top, "list is empty");
// Get the next available index
--- a/hotspot/src/share/vm/gc/parallel/psCompactionManager.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psCompactionManager.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -109,6 +109,10 @@
Action _action;
+ HeapWord* _last_query_beg;
+ oop _last_query_obj;
+ size_t _last_query_ret;
+
static PSOldGen* old_gen() { return _old_gen; }
static ObjectStartArray* start_array() { return _start_array; }
static OopTaskQueueSet* stack_array() { return _stack_array; }
@@ -127,9 +131,26 @@
// marking stack and overflow stack directly.
public:
+ void reset_bitmap_query_cache() {
+ _last_query_beg = NULL;
+ _last_query_obj = NULL;
+ _last_query_ret = 0;
+ }
+
Action action() { return _action; }
void set_action(Action v) { _action = v; }
+ // Bitmap query support, cache last query and result
+ HeapWord* last_query_begin() { return _last_query_beg; }
+ oop last_query_object() { return _last_query_obj; }
+ size_t last_query_return() { return _last_query_ret; }
+
+ void set_last_query_begin(HeapWord *new_beg) { _last_query_beg = new_beg; }
+ void set_last_query_object(oop new_obj) { _last_query_obj = new_obj; }
+ void set_last_query_return(size_t new_ret) { _last_query_ret = new_ret; }
+
+ static void reset_all_bitmap_query_caches();
+
RegionTaskQueue* region_stack() { return _region_stack; }
void set_region_stack(RegionTaskQueue* v) { _region_stack = v; }
--- a/hotspot/src/share/vm/gc/parallel/psCompactionManager.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psCompactionManager.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, 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
@@ -144,7 +144,7 @@
}
inline void ParCompactionManager::update_contents(oop obj) {
- obj->pc_update_contents();
+ obj->pc_update_contents(this);
}
#endif // SHARE_VM_GC_PARALLEL_PSCOMPACTIONMANAGER_INLINE_HPP
--- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -99,7 +99,7 @@
heap->collector_policy()->should_clear_all_soft_refs();
uint count = maximum_heap_compaction ? 1 : MarkSweepAlwaysCompactCount;
- UIntXFlagSetting flag_setting(MarkSweepAlwaysCompactCount, count);
+ UIntFlagSetting flag_setting(MarkSweepAlwaysCompactCount, count);
PSMarkSweep::invoke_no_policy(clear_all_soft_refs || maximum_heap_compaction);
}
@@ -156,8 +156,6 @@
old_gen->verify_object_start_array();
}
- heap->pre_full_gc_dump(_gc_timer);
-
// Filled in below to track the state of the young gen after the collection.
bool eden_empty;
bool survivors_empty;
@@ -168,6 +166,9 @@
GCTraceCPUTime tcpu;
GCTraceTime(Info, gc) t("Pause Full", NULL, gc_cause, true);
+
+ heap->pre_full_gc_dump(_gc_timer);
+
TraceCollectorStats tcs(counters());
TraceMemoryManagerStats tms(true /* Full GC */,gc_cause);
@@ -345,6 +346,8 @@
// Track memory usage and detect low memory
MemoryService::track_memory_usage();
heap->update_counters();
+
+ heap->post_full_gc_dump(_gc_timer);
}
if (VerifyAfterGC && heap->total_collections() >= VerifyGCStartAt) {
@@ -367,8 +370,6 @@
heap->print_heap_after_gc();
heap->trace_heap_after_gc(_gc_tracer);
- heap->post_full_gc_dump(_gc_timer);
-
#ifdef TRACESPINNING
ParallelTaskTerminator::print_termination_counts();
#endif
--- a/hotspot/src/share/vm/gc/parallel/psOldGen.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psOldGen.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "gc/parallel/objectStartArray.inline.hpp"
#include "gc/parallel/parallelScavengeHeap.hpp"
#include "gc/parallel/psAdaptiveSizePolicy.hpp"
#include "gc/parallel/psMarkSweepDecorator.hpp"
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -195,7 +195,7 @@
};
void PSParallelCompact::print_region_ranges() {
- if (!develop_log_is_enabled(Trace, gc, compaction, phases)) {
+ if (!log_develop_is_enabled(Trace, gc, compaction, phases)) {
return;
}
LogHandle(gc, compaction, phases) log;
@@ -265,7 +265,7 @@
print_generic_summary_data(ParallelCompactData& summary_data,
SpaceInfo* space_info)
{
- if (!develop_log_is_enabled(Trace, gc, compaction, phases)) {
+ if (!log_develop_is_enabled(Trace, gc, compaction, phases)) {
return;
}
@@ -360,7 +360,7 @@
void
print_initial_summary_data(ParallelCompactData& summary_data,
SpaceInfo* space_info) {
- if (!develop_log_is_enabled(Trace, gc, compaction, phases)) {
+ if (!log_develop_is_enabled(Trace, gc, compaction, phases)) {
return;
}
@@ -641,7 +641,7 @@
*target_next = split_destination + partial_obj_size;
HeapWord* const source_next = region_to_addr(split_region) + partial_obj_size;
- if (develop_log_is_enabled(Trace, gc, compaction, phases)) {
+ if (log_develop_is_enabled(Trace, gc, compaction, phases)) {
const char * split_type = partial_obj_size == 0 ? "easy" : "hard";
log_develop_trace(gc, compaction, phases)("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT " pos=" SIZE_FORMAT,
split_type, p2i(source_next), split_region, partial_obj_size);
@@ -751,7 +751,7 @@
return true;
}
-HeapWord* ParallelCompactData::calc_new_pointer(HeapWord* addr) {
+HeapWord* ParallelCompactData::calc_new_pointer(HeapWord* addr, ParCompactionManager* cm) {
assert(addr != NULL, "Should detect NULL oop earlier");
assert(ParallelScavengeHeap::heap()->is_in(addr), "not in heap");
assert(PSParallelCompact::mark_bitmap()->is_marked(addr), "not marked");
@@ -788,7 +788,7 @@
const size_t block_offset = addr_to_block_ptr(addr)->offset();
const ParMarkBitMap* bitmap = PSParallelCompact::mark_bitmap();
- const size_t live = bitmap->live_words_in_range(search_start, oop(addr));
+ const size_t live = bitmap->live_words_in_range(cm, search_start, oop(addr));
result += block_offset + live;
DEBUG_ONLY(PSParallelCompact::check_new_location(addr, result));
return result;
@@ -825,11 +825,9 @@
bool PSParallelCompact::IsAliveClosure::do_object_b(oop p) { return mark_bitmap()->is_marked(p); }
-PSParallelCompact::AdjustPointerClosure PSParallelCompact::_adjust_pointer_closure;
-PSParallelCompact::AdjustKlassClosure PSParallelCompact::_adjust_klass_closure;
-
void PSParallelCompact::AdjustKlassClosure::do_klass(Klass* klass) {
- klass->oops_do(&PSParallelCompact::_adjust_pointer_closure);
+ PSParallelCompact::AdjustPointerClosure closure(_cm);
+ klass->oops_do(&closure);
}
void PSParallelCompact::post_initialize() {
@@ -977,6 +975,8 @@
// Have worker threads release resources the next time they run a task.
gc_task_manager()->release_all_resources();
+
+ ParCompactionManager::reset_all_bitmap_query_caches();
}
void PSParallelCompact::post_compact()
@@ -1535,7 +1535,7 @@
}
}
- if (develop_log_is_enabled(Trace, gc, compaction, phases)) {
+ if (log_develop_is_enabled(Trace, gc, compaction, phases)) {
const size_t region_size = ParallelCompactData::RegionSize;
HeapWord* const dense_prefix_end = _space_info[id].dense_prefix();
const size_t dp_region = _summary_data.addr_to_region_idx(dense_prefix_end);
@@ -1746,8 +1746,6 @@
heap->record_gen_tops_before_GC();
}
- heap->pre_full_gc_dump(&_gc_timer);
-
// Make sure data structures are sane, make the heap parsable, and do other
// miscellaneous bookkeeping.
pre_compact();
@@ -1768,6 +1766,9 @@
GCTraceCPUTime tcpu;
GCTraceTime(Info, gc) tm("Pause Full", NULL, gc_cause, true);
+
+ heap->pre_full_gc_dump(&_gc_timer);
+
TraceCollectorStats tcs(counters());
TraceMemoryManagerStats tms(true /* Full GC */,gc_cause);
@@ -1801,7 +1802,7 @@
// adjust_roots() updates Universe::_intArrayKlassObj which is
// needed by the compaction for filling holes in the dense prefix.
- adjust_roots();
+ adjust_roots(vmthread_cm);
compaction_start.update();
compact();
@@ -1902,6 +1903,8 @@
MemoryService::track_memory_usage();
heap->update_counters();
gc_task_manager()->release_idle_workers();
+
+ heap->post_full_gc_dump(&_gc_timer);
}
#ifdef ASSERT
@@ -1940,8 +1943,6 @@
collection_exit.ticks());
gc_task_manager()->print_task_time_stamps();
- heap->post_full_gc_dump(&_gc_timer);
-
#ifdef TRACESPINNING
ParallelTaskTerminator::print_termination_counts();
#endif
@@ -2142,39 +2143,42 @@
};
static PSAlwaysTrueClosure always_true;
-void PSParallelCompact::adjust_roots() {
+void PSParallelCompact::adjust_roots(ParCompactionManager* cm) {
// Adjust the pointers to reflect the new locations
GCTraceTime(Trace, gc, phases) tm("Adjust Roots", &_gc_timer);
// Need new claim bits when tracing through and adjusting pointers.
ClassLoaderDataGraph::clear_claimed_marks();
+ PSParallelCompact::AdjustPointerClosure oop_closure(cm);
+ PSParallelCompact::AdjustKlassClosure klass_closure(cm);
+
// General strong roots.
- Universe::oops_do(adjust_pointer_closure());
- JNIHandles::oops_do(adjust_pointer_closure()); // Global (strong) JNI handles
- CLDToOopClosure adjust_from_cld(adjust_pointer_closure());
- Threads::oops_do(adjust_pointer_closure(), &adjust_from_cld, NULL);
- ObjectSynchronizer::oops_do(adjust_pointer_closure());
- FlatProfiler::oops_do(adjust_pointer_closure());
- Management::oops_do(adjust_pointer_closure());
- JvmtiExport::oops_do(adjust_pointer_closure());
- SystemDictionary::oops_do(adjust_pointer_closure());
- ClassLoaderDataGraph::oops_do(adjust_pointer_closure(), adjust_klass_closure(), true);
+ Universe::oops_do(&oop_closure);
+ JNIHandles::oops_do(&oop_closure); // Global (strong) JNI handles
+ CLDToOopClosure adjust_from_cld(&oop_closure);
+ Threads::oops_do(&oop_closure, &adjust_from_cld, NULL);
+ ObjectSynchronizer::oops_do(&oop_closure);
+ FlatProfiler::oops_do(&oop_closure);
+ Management::oops_do(&oop_closure);
+ JvmtiExport::oops_do(&oop_closure);
+ SystemDictionary::oops_do(&oop_closure);
+ ClassLoaderDataGraph::oops_do(&oop_closure, &klass_closure, true);
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
// Global (weak) JNI handles
- JNIHandles::weak_oops_do(&always_true, adjust_pointer_closure());
-
- CodeBlobToOopClosure adjust_from_blobs(adjust_pointer_closure(), CodeBlobToOopClosure::FixRelocations);
+ JNIHandles::weak_oops_do(&always_true, &oop_closure);
+
+ CodeBlobToOopClosure adjust_from_blobs(&oop_closure, CodeBlobToOopClosure::FixRelocations);
CodeCache::blobs_do(&adjust_from_blobs);
- StringTable::oops_do(adjust_pointer_closure());
- ref_processor()->weak_oops_do(adjust_pointer_closure());
+ StringTable::oops_do(&oop_closure);
+ ref_processor()->weak_oops_do(&oop_closure);
// Roots were visited so references into the young gen in roots
// may have been scanned. Process them also.
// Should the reference processor have a span that excludes
// young gen objects?
- PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure());
+ PSScavenge::reference_processor()->weak_oops_do(&oop_closure);
}
// Helper class to print 8 region numbers per line and then print the total at the end.
@@ -2187,7 +2191,7 @@
bool _enabled;
size_t _total_regions;
public:
- FillableRegionLogger() : _next_index(0), _total_regions(0), _enabled(develop_log_is_enabled(Trace, gc, compaction)) { }
+ FillableRegionLogger() : _next_index(0), _total_regions(0), _enabled(log_develop_is_enabled(Trace, gc, compaction)) { }
~FillableRegionLogger() {
log.trace(SIZE_FORMAT " initially fillable regions", _total_regions);
}
@@ -2378,7 +2382,7 @@
// region.
void PSParallelCompact::write_block_fill_histogram()
{
- if (!develop_log_is_enabled(Trace, gc, compaction)) {
+ if (!log_develop_is_enabled(Trace, gc, compaction)) {
return;
}
@@ -3062,18 +3066,20 @@
update_state(words);
}
-void InstanceKlass::oop_pc_update_pointers(oop obj) {
- oop_oop_iterate_oop_maps<true>(obj, PSParallelCompact::adjust_pointer_closure());
+void InstanceKlass::oop_pc_update_pointers(oop obj, ParCompactionManager* cm) {
+ PSParallelCompact::AdjustPointerClosure closure(cm);
+ oop_oop_iterate_oop_maps<true>(obj, &closure);
}
-void InstanceMirrorKlass::oop_pc_update_pointers(oop obj) {
- InstanceKlass::oop_pc_update_pointers(obj);
-
- oop_oop_iterate_statics<true>(obj, PSParallelCompact::adjust_pointer_closure());
+void InstanceMirrorKlass::oop_pc_update_pointers(oop obj, ParCompactionManager* cm) {
+ InstanceKlass::oop_pc_update_pointers(obj, cm);
+
+ PSParallelCompact::AdjustPointerClosure closure(cm);
+ oop_oop_iterate_statics<true>(obj, &closure);
}
-void InstanceClassLoaderKlass::oop_pc_update_pointers(oop obj) {
- InstanceKlass::oop_pc_update_pointers(obj);
+void InstanceClassLoaderKlass::oop_pc_update_pointers(oop obj, ParCompactionManager* cm) {
+ InstanceKlass::oop_pc_update_pointers(obj, cm);
}
#ifdef ASSERT
@@ -3092,33 +3098,34 @@
#endif
template <class T>
-static void oop_pc_update_pointers_specialized(oop obj) {
+static void oop_pc_update_pointers_specialized(oop obj, ParCompactionManager* cm) {
T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj);
- PSParallelCompact::adjust_pointer(referent_addr);
+ PSParallelCompact::adjust_pointer(referent_addr, cm);
T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj);
- PSParallelCompact::adjust_pointer(next_addr);
+ PSParallelCompact::adjust_pointer(next_addr, cm);
T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj);
- PSParallelCompact::adjust_pointer(discovered_addr);
+ PSParallelCompact::adjust_pointer(discovered_addr, cm);
debug_only(trace_reference_gc("InstanceRefKlass::oop_update_ptrs", obj,
referent_addr, next_addr, discovered_addr);)
}
-void InstanceRefKlass::oop_pc_update_pointers(oop obj) {
- InstanceKlass::oop_pc_update_pointers(obj);
+void InstanceRefKlass::oop_pc_update_pointers(oop obj, ParCompactionManager* cm) {
+ InstanceKlass::oop_pc_update_pointers(obj, cm);
if (UseCompressedOops) {
- oop_pc_update_pointers_specialized<narrowOop>(obj);
+ oop_pc_update_pointers_specialized<narrowOop>(obj, cm);
} else {
- oop_pc_update_pointers_specialized<oop>(obj);
+ oop_pc_update_pointers_specialized<oop>(obj, cm);
}
}
-void ObjArrayKlass::oop_pc_update_pointers(oop obj) {
+void ObjArrayKlass::oop_pc_update_pointers(oop obj, ParCompactionManager* cm) {
assert(obj->is_objArray(), "obj must be obj array");
- oop_oop_iterate_elements<true>(objArrayOop(obj), PSParallelCompact::adjust_pointer_closure());
+ PSParallelCompact::AdjustPointerClosure closure(cm);
+ oop_oop_iterate_elements<true>(objArrayOop(obj), &closure);
}
-void TypeArrayKlass::oop_pc_update_pointers(oop obj) {
+void TypeArrayKlass::oop_pc_update_pointers(oop obj, ParCompactionManager* cm) {
assert(obj->is_typeArray(),"must be a type array");
}
@@ -3128,7 +3135,7 @@
assert(bitmap()->obj_size(addr) == words, "bad size");
_source = addr;
- assert(PSParallelCompact::summary_data().calc_new_pointer(source()) ==
+ assert(PSParallelCompact::summary_data().calc_new_pointer(source(), compaction_manager()) ==
destination(), "wrong destination");
if (words > words_remaining()) {
@@ -3169,3 +3176,14 @@
do_addr(addr);
return ParMarkBitMap::incomplete;
}
+
+ParMarkBitMapClosure::IterationStatus
+FillClosure::do_addr(HeapWord* addr, size_t size) {
+ CollectedHeap::fill_with_objects(addr, size);
+ HeapWord* const end = addr + size;
+ do {
+ _start_array->allocate_block(addr);
+ addr += oop(addr)->size();
+ } while (addr < end);
+ return ParMarkBitMap::incomplete;
+}
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -451,10 +451,10 @@
HeapWord* partial_obj_end(size_t region_idx) const;
// Return the location of the object after compaction.
- HeapWord* calc_new_pointer(HeapWord* addr);
+ HeapWord* calc_new_pointer(HeapWord* addr, ParCompactionManager* cm);
- HeapWord* calc_new_pointer(oop p) {
- return calc_new_pointer((HeapWord*) p);
+ HeapWord* calc_new_pointer(oop p, ParCompactionManager* cm) {
+ return calc_new_pointer((HeapWord*) p, cm);
}
#ifdef ASSERT
@@ -937,17 +937,29 @@
class AdjustPointerClosure: public ExtendedOopClosure {
public:
+ AdjustPointerClosure(ParCompactionManager* cm) {
+ assert(cm != NULL, "associate ParCompactionManage should not be NULL");
+ _cm = cm;
+ }
template <typename T> void do_oop_nv(T* p);
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
// This closure provides its own oop verification code.
debug_only(virtual bool should_verify_oops() { return false; })
+ private:
+ ParCompactionManager* _cm;
};
class AdjustKlassClosure : public KlassClosure {
public:
+ AdjustKlassClosure(ParCompactionManager* cm) {
+ assert(cm != NULL, "associate ParCompactionManage should not be NULL");
+ _cm = cm;
+ }
void do_klass(Klass* klass);
+ private:
+ ParCompactionManager* _cm;
};
friend class AdjustPointerClosure;
@@ -966,8 +978,6 @@
static ParallelCompactData _summary_data;
static IsAliveClosure _is_alive_closure;
static SpaceInfo _space_info[last_space_id];
- static AdjustPointerClosure _adjust_pointer_closure;
- static AdjustKlassClosure _adjust_klass_closure;
// Reference processing (used in ...follow_contents)
static ReferenceProcessor* _ref_processor;
@@ -1063,7 +1073,7 @@
static void summary_phase(ParCompactionManager* cm, bool maximum_compaction);
// Adjust addresses in roots. Does not adjust addresses in heap.
- static void adjust_roots();
+ static void adjust_roots(ParCompactionManager* cm);
DEBUG_ONLY(static void write_block_fill_histogram();)
@@ -1109,10 +1119,6 @@
static bool initialize();
// Closure accessors
- static PSParallelCompact::AdjustPointerClosure* adjust_pointer_closure() {
- return &_adjust_pointer_closure;
- }
- static KlassClosure* adjust_klass_closure() { return (KlassClosure*)&_adjust_klass_closure; }
static BoolObjectClosure* is_alive_closure() { return (BoolObjectClosure*)&_is_alive_closure; }
// Public accessors
@@ -1127,7 +1133,7 @@
static inline bool mark_obj(oop obj);
static inline bool is_marked(oop obj);
- template <class T> static inline void adjust_pointer(T* p);
+ template <class T> static inline void adjust_pointer(T* p, ParCompactionManager* cm);
// Compaction support.
// Return true if p is in the range [beg_addr, end_addr).
@@ -1242,16 +1248,6 @@
#endif // #ifdef ASSERT
};
-inline bool PSParallelCompact::mark_obj(oop obj) {
- const int obj_size = obj->size();
- if (mark_bitmap()->mark_obj(obj, obj_size)) {
- _summary_data.add_obj(obj, obj_size);
- return true;
- } else {
- return false;
- }
-}
-
inline bool PSParallelCompact::is_marked(oop obj) {
return mark_bitmap()->is_marked(obj);
}
@@ -1386,9 +1382,8 @@
inline void do_addr(HeapWord* addr);
};
-class FillClosure: public ParMarkBitMapClosure
-{
-public:
+class FillClosure: public ParMarkBitMapClosure {
+ public:
FillClosure(ParCompactionManager* cm, PSParallelCompact::SpaceId space_id) :
ParMarkBitMapClosure(PSParallelCompact::mark_bitmap(), cm),
_start_array(PSParallelCompact::start_array(space_id))
@@ -1397,17 +1392,9 @@
"cannot use FillClosure in the young gen");
}
- virtual IterationStatus do_addr(HeapWord* addr, size_t size) {
- CollectedHeap::fill_with_objects(addr, size);
- HeapWord* const end = addr + size;
- do {
- _start_array->allocate_block(addr);
- addr += oop(addr)->size();
- } while (addr < end);
- return ParMarkBitMap::incomplete;
- }
+ virtual IterationStatus do_addr(HeapWord* addr, size_t size);
-private:
+ private:
ObjectStartArray* const _start_array;
};
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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,14 +31,24 @@
#include "oops/klass.hpp"
#include "oops/oop.inline.hpp"
+inline bool PSParallelCompact::mark_obj(oop obj) {
+ const int obj_size = obj->size();
+ if (mark_bitmap()->mark_obj(obj, obj_size)) {
+ _summary_data.add_obj(obj, obj_size);
+ return true;
+ } else {
+ return false;
+ }
+}
+
template <class T>
-inline void PSParallelCompact::adjust_pointer(T* p) {
+inline void PSParallelCompact::adjust_pointer(T* p, ParCompactionManager* cm) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
assert(ParallelScavengeHeap::heap()->is_in(obj), "should be in heap");
- oop new_obj = (oop)summary_data().calc_new_pointer(obj);
+ oop new_obj = (oop)summary_data().calc_new_pointer(obj, cm);
assert(new_obj != NULL, // is forwarding ptr?
"should be forwarded");
// Just always do the update unconditionally?
@@ -52,7 +62,7 @@
template <typename T>
void PSParallelCompact::AdjustPointerClosure::do_oop_nv(T* p) {
- adjust_pointer(p);
+ adjust_pointer(p, _cm);
}
inline void PSParallelCompact::AdjustPointerClosure::do_oop(oop* p) { do_oop_nv(p); }
--- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -130,7 +130,7 @@
void
PSPromotionManager::print_taskqueue_stats() {
- if (!develop_log_is_enabled(Trace, gc, task, stats)) {
+ if (!log_develop_is_enabled(Trace, gc, task, stats)) {
return;
}
LogHandle(gc, task, stats) log;
--- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -284,7 +284,7 @@
// This code must come after the CAS test, or it will print incorrect
// information.
- if (develop_log_is_enabled(Trace, gc, scavenge) && o->is_forwarded()) {
+ if (log_develop_is_enabled(Trace, gc, scavenge) && o->is_forwarded()) {
log_develop_trace(gc, scavenge)("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}",
"forwarding",
new_obj->klass()->internal_name(), p2i((void *)o), p2i((void *)new_obj), new_obj->size());
--- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -30,7 +30,7 @@
#include "gc/parallel/parallelScavengeHeap.hpp"
#include "gc/parallel/psAdaptiveSizePolicy.hpp"
#include "gc/parallel/psMarkSweep.hpp"
-#include "gc/parallel/psParallelCompact.hpp"
+#include "gc/parallel/psParallelCompact.inline.hpp"
#include "gc/parallel/psScavenge.inline.hpp"
#include "gc/parallel/psTasks.hpp"
#include "gc/shared/collectorPolicy.hpp"
@@ -763,6 +763,15 @@
return ParallelScavengeHeap::gc_task_manager();
}
+// Adaptive size policy support. When the young generation/old generation
+// boundary moves, _young_generation_boundary must be reset
+void PSScavenge::set_young_generation_boundary(HeapWord* v) {
+ _young_generation_boundary = v;
+ if (UseCompressedOops) {
+ _young_generation_boundary_compressed = (uintptr_t)oopDesc::encode_heap_oop((oop)v);
+ }
+}
+
void PSScavenge::initialize() {
// Arguments must have been parsed
--- a/hotspot/src/share/vm/gc/parallel/psScavenge.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -117,12 +117,7 @@
}
// Adaptive size policy support. When the young generation/old generation
// boundary moves, _young_generation_boundary must be reset
- static void set_young_generation_boundary(HeapWord* v) {
- _young_generation_boundary = v;
- if (UseCompressedOops) {
- _young_generation_boundary_compressed = (uintptr_t)oopDesc::encode_heap_oop((oop)v);
- }
- }
+ static void set_young_generation_boundary(HeapWord* v);
// Called by parallelScavengeHeap to init the tenuring threshold
static void initialize();
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "gc/serial/defNewGeneration.inline.hpp"
+#include "gc/shared/ageTable.inline.hpp"
#include "gc/shared/cardTableRS.hpp"
#include "gc/shared/collectorCounters.hpp"
#include "gc/shared/gcHeapSummary.hpp"
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -285,9 +285,6 @@
// Save the tops for eden, from, and to
virtual void record_spaces_top();
- // Doesn't require additional work during GC prologue and epilogue
- virtual bool performs_in_place_marking() const { return false; }
-
// Accessing marks
void save_marks();
void reset_saved_marks();
--- a/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -176,8 +176,12 @@
SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer();
gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
+ gch->pre_full_gc_dump(gc_timer);
+
GenMarkSweep::invoke_at_safepoint(ref_processor(), clear_all_soft_refs);
+ gch->post_full_gc_dump(gc_timer);
+
gc_timer->register_gc_end();
gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
--- a/hotspot/src/share/vm/gc/shared/ageTable.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/ageTable.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -23,15 +23,16 @@
*/
#include "precompiled.hpp"
-#include "gc/shared/ageTable.hpp"
+#include "gc/shared/ageTable.inline.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/collectorPolicy.hpp"
#include "gc/shared/gcPolicyCounters.hpp"
#include "memory/resourceArea.hpp"
#include "logging/log.hpp"
+#include "oops/oop.inline.hpp"
#include "utilities/copy.hpp"
-/* Copyright (c) 1992, 2015, Oracle and/or its affiliates, and Stanford University.
+/* Copyright (c) 1992, 2016, Oracle and/or its affiliates, and Stanford University.
See the LICENSE file for license information. */
AgeTable::AgeTable(bool global) {
--- a/hotspot/src/share/vm/gc/shared/ageTable.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/ageTable.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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,7 +31,7 @@
class GCPolicyCounters;
-/* Copyright (c) 1992, 2015, Oracle and/or its affiliates, and Stanford University.
+/* Copyright (c) 1992, 2016, Oracle and/or its affiliates, and Stanford University.
See the LICENSE file for license information. */
// Age table for adaptive feedback-mediated tenuring (scavenging)
@@ -56,9 +56,7 @@
void clear();
// add entry
- void add(oop p, size_t oop_size) {
- add(p->age(), oop_size);
- }
+ inline void add(oop p, size_t oop_size);
void add(uint age, size_t oop_size) {
assert(age > 0 && age < table_size, "invalid age of object");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/shared/ageTable.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_AGETABLE_INLINE_HPP
+#define SHARE_VM_GC_SHARED_AGETABLE_INLINE_HPP
+
+#include "gc/shared/ageTable.hpp"
+#include "oops/oop.inline.hpp"
+
+// add entry
+void AgeTable::add(oop p, size_t oop_size) {
+ add(p->age(), oop_size);
+}
+
+#endif // SHARE_VM_GC_SHARED_AGETABLE_INLINE_HPP
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -571,30 +571,28 @@
}
}
-void CollectedHeap::full_gc_dump(GCTimer* timer, const char* when) {
- if (HeapDumpBeforeFullGC || HeapDumpAfterFullGC) {
- GCIdMarkAndRestore gc_id_mark;
- FormatBuffer<> title("Heap Dump (%s full gc)", when);
- GCTraceTime(Info, gc) tm(title.buffer(), timer);
+void CollectedHeap::full_gc_dump(GCTimer* timer, bool before) {
+ assert(timer != NULL, "timer is null");
+ if ((HeapDumpBeforeFullGC && before) || (HeapDumpAfterFullGC && !before)) {
+ GCTraceTime(Info, gc) tm(before ? "Heap Dump (before full gc)" : "Heap Dump (after full gc)", timer);
HeapDumper::dump_heap();
}
+
LogHandle(gc, classhisto) log;
if (log.is_trace()) {
+ GCTraceTime(Trace, gc, classhisto) tm(before ? "Class Histogram (before full gc)" : "Class Histogram (after full gc)", timer);
ResourceMark rm;
- GCIdMarkAndRestore gc_id_mark;
- FormatBuffer<> title("Class Histogram (%s full gc)", when);
- GCTraceTime(Trace, gc, classhisto) tm(title.buffer(), timer);
VM_GC_HeapInspection inspector(log.trace_stream(), false /* ! full gc */);
inspector.doit();
}
}
void CollectedHeap::pre_full_gc_dump(GCTimer* timer) {
- full_gc_dump(timer, "before");
+ full_gc_dump(timer, true);
}
void CollectedHeap::post_full_gc_dump(GCTimer* timer) {
- full_gc_dump(timer, "after");
+ full_gc_dump(timer, false);
}
void CollectedHeap::initialize_reserved_region(HeapWord *start, HeapWord *end) {
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -525,7 +525,7 @@
// Generate any dumps preceding or following a full gc
private:
- void full_gc_dump(GCTimer* timer, const char* when);
+ void full_gc_dump(GCTimer* timer, bool before);
public:
void pre_full_gc_dump(GCTimer* timer);
void post_full_gc_dump(GCTimer* timer);
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -30,6 +30,7 @@
#include "gc/shared/threadLocalAllocBuffer.inline.hpp"
#include "memory/universe.hpp"
#include "oops/arrayOop.hpp"
+#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/thread.inline.hpp"
@@ -248,7 +249,7 @@
assert(is_size_aligned(alignment_in_bytes, HeapWordSize),
"Alignment size %u is incorrect.", alignment_in_bytes);
- HeapWord* new_addr = (HeapWord*) align_pointer_up(addr, alignment_in_bytes);
+ HeapWord* new_addr = (HeapWord*) align_ptr_up(addr, alignment_in_bytes);
size_t padding = pointer_delta(new_addr, addr);
if (padding == 0) {
--- a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -774,7 +774,7 @@
// free memory should be here, especially if they are expensive. If this
// attempt fails, an OOM exception will be thrown.
{
- UIntXFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted
+ UIntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted
gch->do_collection(true, // full
true, // clear_all_soft_refs
--- a/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -145,24 +145,9 @@
virtual CardTableRS* create_rem_set(MemRegion reserved);
- // This method controls how a collector satisfies a request
- // for a block of memory. "gc_time_limit_was_exceeded" will
- // be set to true if the adaptive size policy determine that
- // an excessive amount of time is being spent doing collections
- // and caused a NULL to be returned. If a NULL is not returned,
- // "gc_time_limit_was_exceeded" has an undefined meaning.
- virtual HeapWord* mem_allocate_work(size_t size,
- bool is_tlab,
- bool* gc_overhead_limit_was_exceeded) = 0;
-
- // This method controls how a collector handles one or more
- // of its generations being fully allocated.
- virtual HeapWord *satisfy_failed_allocation(size_t size, bool is_tlab) = 0;
- // This method controls how a collector handles a metadata allocation
- // failure.
- virtual MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data,
- size_t size,
- Metaspace::MetadataType mdtype);
+ MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data,
+ size_t size,
+ Metaspace::MetadataType mdtype);
// Performance Counter support
GCPolicyCounters* counters() { return _gc_policy_counters; }
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -289,9 +289,9 @@
HeapWord* GenCollectedHeap::mem_allocate(size_t size,
bool* gc_overhead_limit_was_exceeded) {
- return collector_policy()->mem_allocate_work(size,
- false /* is_tlab */,
- gc_overhead_limit_was_exceeded);
+ return gen_policy()->mem_allocate_work(size,
+ false /* is_tlab */,
+ gc_overhead_limit_was_exceeded);
}
bool GenCollectedHeap::must_clear_all_soft_refs() {
@@ -458,7 +458,6 @@
prepared_for_verification = true;
}
- assert(!_young_gen->performs_in_place_marking(), "No young generation do in place marking");
collect_generation(_young_gen,
full,
size,
@@ -482,15 +481,11 @@
increment_total_full_collections();
}
- pre_full_gc_dump(NULL); // do any pre full gc dumps
-
if (!prepared_for_verification && run_verification &&
VerifyGCLevel <= 1 && VerifyBeforeGC) {
prepare_for_verify();
}
- assert(_old_gen->performs_in_place_marking(), "All old generations do in place marking");
-
if (do_young_collection) {
// We did a young GC. Need a new GC id for the old GC.
GCIdMarkAndRestore gc_id_mark;
@@ -510,11 +505,6 @@
// a whole heap collection.
complete = complete || collected_old;
- if (complete) { // We did a full collection
- // FIXME: See comment at pre_full_gc_dump call
- post_full_gc_dump(NULL); // do any post full gc dumps
- }
-
print_heap_change(young_prev_used, old_prev_used);
MetaspaceAux::print_metaspace_change(metadata_prev_used);
@@ -551,7 +541,7 @@
}
HeapWord* GenCollectedHeap::satisfy_failed_allocation(size_t size, bool is_tlab) {
- return collector_policy()->satisfy_failed_allocation(size, is_tlab);
+ return gen_policy()->satisfy_failed_allocation(size, is_tlab);
}
#ifdef ASSERT
@@ -988,9 +978,9 @@
HeapWord* GenCollectedHeap::allocate_new_tlab(size_t size) {
bool gc_overhead_limit_was_exceeded;
- return collector_policy()->mem_allocate_work(size /* size */,
- true /* is_tlab */,
- &gc_overhead_limit_was_exceeded);
+ return gen_policy()->mem_allocate_work(size /* size */,
+ true /* is_tlab */,
+ &gc_overhead_limit_was_exceeded);
}
// Requires "*prev_ptr" to be non-NULL. Deletes and a block of minimal size
--- a/hotspot/src/share/vm/gc/shared/genOopClosures.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/genOopClosures.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -146,23 +146,15 @@
HeapWord* _boundary;
ExtendedOopClosure* _cl;
protected:
- template <class T> inline void do_oop_work(T* p) {
- T heap_oop = oopDesc::load_heap_oop(p);
- if (!oopDesc::is_null(heap_oop)) {
- oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
- if ((HeapWord*)obj < _boundary) {
- _cl->do_oop(p);
- }
- }
- }
+ template <class T> inline void do_oop_work(T* p);
public:
FilteringClosure(HeapWord* boundary, ExtendedOopClosure* cl) :
ExtendedOopClosure(cl->ref_processor()), _boundary(boundary),
_cl(cl) {}
virtual void do_oop(oop* p);
virtual void do_oop(narrowOop* p);
- inline void do_oop_nv(oop* p) { FilteringClosure::do_oop_work(p); }
- inline void do_oop_nv(narrowOop* p) { FilteringClosure::do_oop_work(p); }
+ inline void do_oop_nv(oop* p);
+ inline void do_oop_nv(narrowOop* p);
virtual bool do_metadata() { return do_metadata_nv(); }
inline bool do_metadata_nv() { assert(!_cl->do_metadata(), "assumption broken, must change to 'return _cl->do_metadata()'"); return false; }
};
--- a/hotspot/src/share/vm/gc/shared/genOopClosures.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/genOopClosures.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -124,6 +124,19 @@
inline void FastScanClosure::do_oop_nv(oop* p) { FastScanClosure::do_oop_work(p); }
inline void FastScanClosure::do_oop_nv(narrowOop* p) { FastScanClosure::do_oop_work(p); }
+template <class T> void FilteringClosure::do_oop_work(T* p) {
+ T heap_oop = oopDesc::load_heap_oop(p);
+ if (!oopDesc::is_null(heap_oop)) {
+ oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
+ if ((HeapWord*)obj < _boundary) {
+ _cl->do_oop(p);
+ }
+ }
+}
+
+void FilteringClosure::do_oop_nv(oop* p) { FilteringClosure::do_oop_work(p); }
+void FilteringClosure::do_oop_nv(narrowOop* p) { FilteringClosure::do_oop_work(p); }
+
// Note similarity to ScanClosure; the difference is that
// the barrier set is taken care of outside this closure.
template <class T> inline void ScanWeakRefClosure::do_oop_work(T* p) {
--- a/hotspot/src/share/vm/gc/shared/generation.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/generation.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -309,13 +309,6 @@
// do nothing.
virtual void par_oop_since_save_marks_iterate_done(int thread_num) {}
- // This generation does in-place marking, meaning that mark words
- // are mutated during the marking phase and presumably reinitialized
- // to a canonical value after the GC. This is currently used by the
- // biased locking implementation to determine whether additional
- // work is required during the GC prologue and epilogue.
- virtual bool performs_in_place_marking() const { return true; }
-
// Returns "true" iff collect() should subsequently be called on this
// this generation. See comment below.
// This is a generic implementation which can be overridden.
--- a/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -30,7 +30,7 @@
#include "gc/shared/gcTimer.hpp"
#include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/referencePolicy.hpp"
-#include "gc/shared/referenceProcessor.hpp"
+#include "gc/shared/referenceProcessor.inline.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "oops/oop.inline.hpp"
--- a/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -58,23 +58,13 @@
class DiscoveredList {
public:
DiscoveredList() : _len(0), _compressed_head(0), _oop_head(NULL) { }
- oop head() const {
- return UseCompressedOops ? oopDesc::decode_heap_oop(_compressed_head) :
- _oop_head;
- }
+ inline oop head() const;
HeapWord* adr_head() {
return UseCompressedOops ? (HeapWord*)&_compressed_head :
(HeapWord*)&_oop_head;
}
- void set_head(oop o) {
- if (UseCompressedOops) {
- // Must compress the head ptr.
- _compressed_head = oopDesc::encode_heap_oop(o);
- } else {
- _oop_head = o;
- }
- }
- bool is_empty() const { return head() == NULL; }
+ inline void set_head(oop o);
+ inline bool is_empty() const;
size_t length() { return _len; }
void set_length(size_t len) { _len = len; }
void inc_length(size_t inc) { _len += inc; assert(_len > 0, "Error"); }
@@ -113,22 +103,7 @@
public:
inline DiscoveredListIterator(DiscoveredList& refs_list,
OopClosure* keep_alive,
- BoolObjectClosure* is_alive):
- _refs_list(refs_list),
- _prev_next(refs_list.adr_head()),
- _prev(NULL),
- _ref(refs_list.head()),
-#ifdef ASSERT
- _first_seen(refs_list.head()),
-#endif
-#ifndef PRODUCT
- _processed(0),
- _removed(0),
-#endif
- _next(NULL),
- _keep_alive(keep_alive),
- _is_alive(is_alive)
-{ }
+ BoolObjectClosure* is_alive);
// End Of List.
inline bool has_next() const { return _ref != NULL; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/shared/referenceProcessor.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_SHARED_REFERENCEPROCESSOR_INLINE_HPP
+#define SHARE_VM_GC_SHARED_REFERENCEPROCESSOR_INLINE_HPP
+
+#include "gc/shared/referenceProcessor.hpp"
+#include "oops/oop.inline.hpp"
+
+oop DiscoveredList::head() const {
+ return UseCompressedOops ? oopDesc::decode_heap_oop(_compressed_head) :
+ _oop_head;
+}
+
+void DiscoveredList::set_head(oop o) {
+ if (UseCompressedOops) {
+ // Must compress the head ptr.
+ _compressed_head = oopDesc::encode_heap_oop(o);
+ } else {
+ _oop_head = o;
+ }
+}
+
+bool DiscoveredList::is_empty() const {
+ return head() == NULL;
+}
+
+DiscoveredListIterator::DiscoveredListIterator(DiscoveredList& refs_list,
+ OopClosure* keep_alive,
+ BoolObjectClosure* is_alive):
+ _refs_list(refs_list),
+ _prev_next(refs_list.adr_head()),
+ _prev(NULL),
+ _ref(refs_list.head()),
+#ifdef ASSERT
+ _first_seen(refs_list.head()),
+#endif
+#ifndef PRODUCT
+ _processed(0),
+ _removed(0),
+#endif
+ _next(NULL),
+ _keep_alive(keep_alive),
+ _is_alive(is_alive) {
+}
+
+#endif // SHARE_VM_GC_SHARED_REFERENCEPROCESSOR_INLINE_HPP
--- a/hotspot/src/share/vm/gc/shared/space.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/space.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -360,9 +360,7 @@
return size;
}
- inline size_t obj_size(const HeapWord* addr) const {
- return oop(addr)->size();
- }
+ inline size_t obj_size(const HeapWord* addr) const;
public:
CompactibleSpace() :
@@ -508,9 +506,7 @@
return true; // Always true, since scan_limit is top
}
- inline size_t scanned_block_size(const HeapWord* addr) const {
- return oop(addr)->size();
- }
+ inline size_t scanned_block_size(const HeapWord* addr) const;
protected:
HeapWord* _top;
--- a/hotspot/src/share/vm/gc/shared/space.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/gc/shared/space.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -72,6 +72,10 @@
return _offsets.block_start(p);
}
+size_t CompactibleSpace::obj_size(const HeapWord* addr) const {
+ return oop(addr)->size();
+}
+
template <class SpaceType>
inline void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp) {
// Compute the new addresses for the live objects and store it in the mark
@@ -331,4 +335,9 @@
if (ZapUnusedHeapArea) space->mangle_unused_area();
}
}
+
+size_t ContiguousSpace::scanned_block_size(const HeapWord* addr) const {
+ return oop(addr)->size();
+}
+
#endif // SHARE_VM_GC_SHARED_SPACE_INLINE_HPP
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -2502,10 +2502,10 @@
// Same comments as invokevirtual apply here.
oop rcvr = STACK_OBJECT(-parms);
VERIFY_OOP(rcvr);
- InstanceKlass* rcvrKlass = (InstanceKlass*)rcvr->klass();
- callee = (Method*) rcvrKlass->start_of_vtable()[ cache->f2_as_index()];
+ Klass* rcvrKlass = rcvr->klass();
+ callee = (Method*) rcvrKlass->method_at_vtable(cache->f2_as_index());
// Profile 'special case of invokeinterface' virtual call.
- BI_PROFILE_UPDATE_VIRTUALCALL(rcvr->klass());
+ BI_PROFILE_UPDATE_VIRTUALCALL(rcvrKlass);
}
istate->set_callee(callee);
istate->set_callee_entry_point(callee->from_interpreted_entry());
@@ -2594,7 +2594,7 @@
// but this works
oop rcvr = STACK_OBJECT(-parms);
VERIFY_OOP(rcvr);
- InstanceKlass* rcvrKlass = (InstanceKlass*)rcvr->klass();
+ Klass* rcvrKlass = rcvr->klass();
/*
Executing this code in java.lang.String:
public String(char value[]) {
@@ -2611,9 +2611,9 @@
However it seems to have a vtable in the right location. Huh?
Because vtables have the same offset for ArrayKlass and InstanceKlass.
*/
- callee = (Method*) rcvrKlass->start_of_vtable()[ cache->f2_as_index()];
+ callee = (Method*) rcvrKlass->method_at_vtable(cache->f2_as_index());
// Profile virtual call.
- BI_PROFILE_UPDATE_VIRTUALCALL(rcvr->klass());
+ BI_PROFILE_UPDATE_VIRTUALCALL(rcvrKlass);
}
} else {
if ((Bytecodes::Code)opcode == Bytecodes::_invokespecial) {
--- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -264,7 +264,7 @@
return true;
}
//climit = cache->length(); // %%% private!
- size_t size = cache->size() * HeapWordSize;
+ size_t size = cache->size() * wordSize;
size -= sizeof(ConstantPoolCache);
size /= sizeof(ConstantPoolCacheEntry);
climit = (int) size;
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -763,7 +763,7 @@
if (cp_cache_entry->is_resolved(bytecode)) return;
if (bytecode == Bytecodes::_invokeinterface) {
- if (develop_log_is_enabled(Trace, itables)) {
+ if (log_develop_is_enabled(Trace, itables)) {
ResourceMark rm(thread);
log_develop_trace(itables)("Resolving: klass: %s to method: %s",
info.resolved_klass()->name()->as_C_string(),
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -168,7 +168,7 @@
} else if (!resolved_klass->is_interface()) {
// A default or miranda method. Compute the vtable index.
ResourceMark rm;
- klassVtable* vt = InstanceKlass::cast(resolved_klass)->vtable();
+ klassVtable* vt = resolved_klass->vtable();
index = LinkResolver::vtable_index_of_interface_method(resolved_klass,
resolved_method);
assert(index >= 0 , "we should have valid vtable index at this point");
@@ -818,7 +818,7 @@
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
- if (develop_log_is_enabled(Trace, itables)) {
+ if (log_develop_is_enabled(Trace, itables)) {
trace_method_resolution("invokeinterface resolved method: caller-class",
link_info.current_klass(), resolved_klass,
resolved_method, true);
@@ -1066,7 +1066,7 @@
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
- if (develop_log_is_enabled(Trace, itables)) {
+ if (log_develop_is_enabled(Trace, itables)) {
trace_method_resolution("invokespecial resolved method: caller-class:",
current_klass, resolved_klass, resolved_method, true);
}
@@ -1137,7 +1137,7 @@
sel_method->signature()));
}
- if (develop_log_is_enabled(Trace, itables)) {
+ if (log_develop_is_enabled(Trace, itables)) {
trace_method_resolution("invokespecial selected method: resolved-class:",
resolved_klass, resolved_klass, sel_method, true);
}
@@ -1190,7 +1190,7 @@
THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
}
- if (develop_log_is_enabled(Trace, vtables)) {
+ if (log_develop_is_enabled(Trace, vtables)) {
trace_method_resolution("invokevirtual resolved method: caller-class:",
current_klass, resolved_klass, resolved_method, false);
}
@@ -1229,8 +1229,7 @@
resolved_method);
assert(vtable_index >= 0 , "we should have valid vtable index at this point");
- InstanceKlass* inst = InstanceKlass::cast(recv_klass());
- selected_method = methodHandle(THREAD, inst->method_at_vtable(vtable_index));
+ selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
} else {
// at this point we are sure that resolved_method is virtual and not
// a default or miranda method; therefore, it must have a valid vtable index.
@@ -1245,10 +1244,7 @@
assert(resolved_method->can_be_statically_bound(), "cannot override this method");
selected_method = resolved_method;
} else {
- // recv_klass might be an arrayKlassOop but all vtables start at
- // the same place. The cast is to avoid virtual call and assertion.
- InstanceKlass* inst = (InstanceKlass*)recv_klass();
- selected_method = methodHandle(THREAD, inst->method_at_vtable(vtable_index));
+ selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
}
}
@@ -1270,7 +1266,7 @@
selected_method->signature()));
}
- if (develop_log_is_enabled(Trace, vtables)) {
+ if (log_develop_is_enabled(Trace, vtables)) {
trace_method_resolution("invokevirtual selected method: receiver-class:",
recv_klass, resolved_klass, selected_method,
false, vtable_index);
@@ -1369,7 +1365,7 @@
sel_method->signature()));
}
- if (develop_log_is_enabled(Trace, itables)) {
+ if (log_develop_is_enabled(Trace, itables)) {
trace_method_resolution("invokeinterface selected method: receiver-class",
recv_klass, resolved_klass, sel_method, true);
}
--- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -546,7 +546,7 @@
// Make sure a valid compile_id is associated with every compile
id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci);
}
- result = JVMCIEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer,
+ result = JVMCIEnv::register_method(method, nm, entry_bci, &_offsets, _orig_pc_offset, &buffer,
stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
compiler, _debug_recorder, _dependencies, env, id,
has_unsafe_access, _has_wide_vector, installed_code, compiled_code, speculation_log);
@@ -576,7 +576,19 @@
_code_handle = JNIHandles::make_local(HotSpotCompiledCode::targetCode(compiled_code));
_code_size = HotSpotCompiledCode::targetCodeSize(compiled_code);
_total_frame_size = HotSpotCompiledCode::totalFrameSize(compiled_code);
- _custom_stack_area_offset = HotSpotCompiledCode::customStackAreaOffset(compiled_code);
+
+ oop deoptRescueSlot = HotSpotCompiledCode::deoptRescueSlot(compiled_code);
+ if (deoptRescueSlot == NULL) {
+ _orig_pc_offset = -1;
+ } else {
+ _orig_pc_offset = StackSlot::offset(deoptRescueSlot);
+ if (StackSlot::addFrameSize(deoptRescueSlot)) {
+ _orig_pc_offset += _total_frame_size;
+ }
+ if (_orig_pc_offset < 0) {
+ JVMCI_ERROR("invalid deopt rescue slot: %d", _orig_pc_offset);
+ }
+ }
// Pre-calculate the constants section size. This is required for PC-relative addressing.
_data_section_handle = JNIHandles::make_local(HotSpotCompiledCode::dataSection(compiled_code));
@@ -724,6 +736,9 @@
if (site_InfopointReason::SAFEPOINT() == reason || site_InfopointReason::CALL() == reason || site_InfopointReason::IMPLICIT_EXCEPTION() == reason) {
TRACE_jvmci_4("safepoint at %i", pc_offset);
site_Safepoint(buffer, pc_offset, site, CHECK_OK);
+ if (_orig_pc_offset < 0) {
+ JVMCI_ERROR_OK("method contains safepoint, but has no deopt rescue slot");
+ }
} else {
TRACE_jvmci_4("infopoint at %i", pc_offset);
site_Infopoint(buffer, pc_offset, site, CHECK_OK);
--- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -125,7 +125,7 @@
jobject _code_handle;
jint _code_size;
jint _total_frame_size;
- jint _custom_stack_area_offset;
+ jint _orig_pc_offset;
jint _parameter_count;
jint _constants_size;
#ifndef PRODUCT
--- a/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -38,7 +38,7 @@
JVMCICompiler::JVMCICompiler() : AbstractCompiler(jvmci) {
_bootstrapping = false;
- _methodsCompiled = 0;
+ _methods_compiled = 0;
assert(_instance == NULL, "only one instance allowed");
_instance = this;
}
@@ -99,7 +99,7 @@
} while (first_round && qsize == 0);
first_round = false;
if (PrintBootstrap) {
- while (z < (_methodsCompiled / 100)) {
+ while (z < (_methods_compiled / 100)) {
++z;
tty->print_raw(".");
}
@@ -107,7 +107,7 @@
} while (qsize != 0);
if (PrintBootstrap) {
- tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)", os::javaTimeMillis() - start, _methodsCompiled);
+ tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)", os::javaTimeMillis() - start, _methods_compiled);
}
_bootstrapping = false;
}
@@ -176,7 +176,7 @@
env->set_failure("no nmethod produced", true);
} else {
env->task()->set_num_inlined_bytecodes(CompilationRequestResult::inlinedBytecodes(result_object));
- _methodsCompiled++;
+ Atomic::inc(&_methods_compiled);
}
}
} else {
--- a/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/jvmciCompiler.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -33,10 +33,10 @@
bool _bootstrapping;
/**
- * Number of methods compiled by JVMCI. This is not synchronized
- * so may not be 100% accurate.
+ * Number of methods successfully compiled by a call to
+ * JVMCICompiler::compile_method().
*/
- volatile int _methodsCompiled;
+ volatile int _methods_compiled;
static JVMCICompiler* _instance;
@@ -80,8 +80,11 @@
// Print compilation timers and statistics
virtual void print_timers();
- // Print compilation statistics
- void reset_compilation_stats();
+ /**
+ * Gets the number of methods that have been successfully compiled by
+ * a call to JVMCICompiler::compile_method().
+ */
+ int methods_compiled() { return _methods_compiled; }
// Print compilation timers and statistics
static void print_compilation_timers();
--- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -121,8 +121,8 @@
extern uint64_t jvmciHotSpotVMAddressEntryArrayStride;
}
-int CompilerToVM::Data::InstanceKlass_vtable_start_offset;
-int CompilerToVM::Data::InstanceKlass_vtable_length_offset;
+int CompilerToVM::Data::Klass_vtable_start_offset;
+int CompilerToVM::Data::Klass_vtable_length_offset;
int CompilerToVM::Data::Method_extra_stack_entries;
@@ -153,8 +153,8 @@
int CompilerToVM::Data::vm_page_size;
void CompilerToVM::Data::initialize() {
- InstanceKlass_vtable_start_offset = InstanceKlass::vtable_start_offset();
- InstanceKlass_vtable_length_offset = InstanceKlass::vtable_length_offset() * HeapWordSize;
+ Klass_vtable_start_offset = in_bytes(Klass::vtable_start_offset());
+ Klass_vtable_length_offset = in_bytes(Klass::vtable_length_offset());
Method_extra_stack_entries = Method::extra_stack_entries();
@@ -659,8 +659,7 @@
vtable_index = LinkResolver::vtable_index_of_interface_method(holder_klass, resolved_method);
assert(vtable_index >= 0 , "we should have valid vtable index at this point");
- InstanceKlass* inst = InstanceKlass::cast(recv_klass);
- selected_method = inst->method_at_vtable(vtable_index);
+ selected_method = recv_klass->method_at_vtable(vtable_index);
} else {
// at this point we are sure that resolved_method is virtual and not
// a miranda method; therefore, it must have a valid vtable index.
@@ -675,10 +674,7 @@
assert(resolved_method->can_be_statically_bound(), "cannot override this method");
selected_method = resolved_method();
} else {
- // recv_klass might be an arrayKlassOop but all vtables start at
- // the same place. The cast is to avoid virtual call and assertion.
- InstanceKlass* inst = (InstanceKlass*)recv_klass;
- selected_method = inst->method_at_vtable(vtable_index);
+ selected_method = recv_klass->method_at_vtable(vtable_index);
}
}
oop result = CompilerToVM::get_jvmci_method(selected_method, CHECK_NULL);
--- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -34,8 +34,8 @@
friend class JVMCIVMStructs;
private:
- static int InstanceKlass_vtable_start_offset;
- static int InstanceKlass_vtable_length_offset;
+ static int Klass_vtable_start_offset;
+ static int Klass_vtable_length_offset;
static int Method_extra_stack_entries;
--- a/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/jvmciJavaClasses.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -91,7 +91,7 @@
objArrayOop_field(HotSpotCompiledCode, dataSectionPatches, "[Ljdk/vm/ci/code/site/DataPatch;") \
boolean_field(HotSpotCompiledCode, isImmutablePIC) \
int_field(HotSpotCompiledCode, totalFrameSize) \
- int_field(HotSpotCompiledCode, customStackAreaOffset) \
+ oop_field(HotSpotCompiledCode, deoptRescueSlot, "Ljdk/vm/ci/code/StackSlot;") \
end_class \
start_class(HotSpotCompiledCode_Comment) \
oop_field(HotSpotCompiledCode_Comment, text, "Ljava/lang/String;") \
--- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -634,6 +634,7 @@
void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(TRAPS) {
if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) {
+ ResourceMark rm;
#ifdef ASSERT
// This should only be called in the context of the JVMCI class being initialized
TempNewSymbol name = SymbolTable::new_symbol("jdk/vm/ci/runtime/JVMCI", CHECK);
--- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -45,8 +45,8 @@
#define VM_STRUCTS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field) \
- static_field(CompilerToVM::Data, InstanceKlass_vtable_start_offset, int) \
- static_field(CompilerToVM::Data, InstanceKlass_vtable_length_offset, int) \
+ static_field(CompilerToVM::Data, Klass_vtable_start_offset, int) \
+ static_field(CompilerToVM::Data, Klass_vtable_length_offset, int) \
\
static_field(CompilerToVM::Data, Method_extra_stack_entries, int) \
\
--- a/hotspot/src/share/vm/logging/log.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/logging/log.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -30,58 +30,61 @@
#include "logging/log.hpp"
#include "logging/logConfiguration.hpp"
+#include "logging/logOutput.hpp"
#include "memory/resourceArea.hpp"
void Test_log_length() {
remove("loglengthoutput.txt");
// Write long message to output file
- LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=trace",
- NULL, NULL, NULL);
ResourceMark rm;
- outputStream* logstream = LogHandle(logging)::trace_stream();
- logstream->print_cr("01:1234567890-"
- "02:1234567890-"
- "03:1234567890-"
- "04:1234567890-"
- "05:1234567890-"
- "06:1234567890-"
- "07:1234567890-"
- "08:1234567890-"
- "09:1234567890-"
- "10:1234567890-"
- "11:1234567890-"
- "12:1234567890-"
- "13:1234567890-"
- "14:1234567890-"
- "15:1234567890-"
- "16:1234567890-"
- "17:1234567890-"
- "18:1234567890-"
- "19:1234567890-"
- "20:1234567890-"
- "21:1234567890-"
- "22:1234567890-"
- "23:1234567890-"
- "24:1234567890-"
- "25:1234567890-"
- "26:1234567890-"
- "27:1234567890-"
- "28:1234567890-"
- "29:1234567890-"
- "30:1234567890-"
- "31:1234567890-"
- "32:1234567890-"
- "33:1234567890-"
- "34:1234567890-"
- "35:1234567890-"
- "36:1234567890-"
- "37:1234567890-");
+ LogHandle(logging) log;
+ bool success = LogConfiguration::parse_log_arguments("loglengthoutput.txt", "logging=trace",
+ NULL, NULL, log.error_stream());
+ assert(success, "test unable to configure logging");
+ log.trace("01:1234567890-"
+ "02:1234567890-"
+ "03:1234567890-"
+ "04:1234567890-"
+ "05:1234567890-"
+ "06:1234567890-"
+ "07:1234567890-"
+ "08:1234567890-"
+ "09:1234567890-"
+ "10:1234567890-"
+ "11:1234567890-"
+ "12:1234567890-"
+ "13:1234567890-"
+ "14:1234567890-"
+ "15:1234567890-"
+ "16:1234567890-"
+ "17:1234567890-"
+ "18:1234567890-"
+ "19:1234567890-"
+ "20:1234567890-"
+ "21:1234567890-"
+ "22:1234567890-"
+ "23:1234567890-"
+ "24:1234567890-"
+ "25:1234567890-"
+ "26:1234567890-"
+ "27:1234567890-"
+ "28:1234567890-"
+ "29:1234567890-"
+ "30:1234567890-"
+ "31:1234567890-"
+ "32:1234567890-"
+ "33:1234567890-"
+ "34:1234567890-"
+ "35:1234567890-"
+ "36:1234567890-"
+ "37:1234567890-");
+ LogConfiguration::parse_log_arguments("loglengthoutput.txt", "all=off",
+ NULL, NULL, log.error_stream());
// Look for end of message in output file
- FILE* fp;
- fp = fopen("loglengthoutput.txt", "r");
- assert (fp, "File read error");
+ FILE* fp = fopen("loglengthoutput.txt", "r");
+ assert(fp, "File read error");
char output[600];
if (fgets(output, 600, fp) != NULL) {
assert(strstr(output, "37:1234567890-"), "logging print size error");
@@ -89,5 +92,48 @@
fclose(fp);
remove("loglengthoutput.txt");
}
+
+#define assert_str_eq(s1, s2) \
+ assert(strcmp(s1, s2) == 0, "Expected '%s' to equal '%s'", s1, s2)
+
+#define assert_char_in(c, s) \
+ assert(strchr(s, c) != NULL, "Expected '%s' to contain character '%c'", s, c)
+
+#define assert_char_not_in(c, s) \
+ assert(strchr(s, c) == NULL, "Expected '%s' to *not* contain character '%c'", s, c)
+
+void Test_configure_stdout() {
+ ResourceMark rm;
+ LogHandle(logging) log;
+ LogOutput* stdoutput = LogOutput::Stdout;
+
+ // Save current stdout config and clear it
+ char* saved_config = os::strdup_check_oom(stdoutput->config_string());
+ LogConfiguration::parse_log_arguments("stdout", "all=off", NULL, NULL, log.error_stream());
+
+ // Enable 'logging=info', verifying it has been set
+ LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(logging));
+ assert_str_eq("logging=info,", stdoutput->config_string());
+ assert(log_is_enabled(Info, logging), "logging was not properly enabled");
+
+ // Enable 'gc=debug' (no wildcard), verifying no other tags are enabled
+ LogConfiguration::configure_stdout(LogLevel::Debug, true, LOG_TAGS(gc));
+ // No '+' character means only single tags are enabled, and no combinations
+ assert_char_not_in('+', stdoutput->config_string());
+ assert(log_is_enabled(Debug, gc), "logging was not properly enabled");
+
+ // Enable 'gc*=trace' (with wildcard), verifying at least one tag combination is enabled (gc+...)
+ LogConfiguration::configure_stdout(LogLevel::Trace, false, LOG_TAGS(gc));
+ assert_char_in('+', stdoutput->config_string());
+ assert(log_is_enabled(Trace, gc), "logging was not properly enabled");
+
+ // Disable 'gc*' and 'logging', verifying all logging is properly disabled
+ LogConfiguration::configure_stdout(LogLevel::Off, false, LOG_TAGS(gc));
+ LogConfiguration::configure_stdout(LogLevel::Off, true, LOG_TAGS(logging));
+ assert_str_eq("all=off", stdoutput->config_string());
+
+ // Restore saved configuration
+ LogConfiguration::parse_log_arguments("stdout", saved_config, NULL, NULL, log.error_stream());
+ os::free(saved_config);
+}
#endif // PRODUCT
-
--- a/hotspot/src/share/vm/logging/log.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/logging/log.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -57,13 +57,13 @@
#define log_develop_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Info>
#define log_develop_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Debug>
#define log_develop_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : Log<LOG_TAGS(__VA_ARGS__)>::write<LogLevel::Trace>
-#define develop_log_is_enabled(level, ...) log_is_enabled(level, __VA_ARGS__)
+#define log_develop_is_enabled(level, ...) log_is_enabled(level, __VA_ARGS__)
#else
#define DUMMY_ARGUMENT_CONSUMER(...)
#define log_develop_info(...) DUMMY_ARGUMENT_CONSUMER
#define log_develop_debug(...) DUMMY_ARGUMENT_CONSUMER
#define log_develop_trace(...) DUMMY_ARGUMENT_CONSUMER
-#define develop_log_is_enabled(...) false
+#define log_develop_is_enabled(...) false
#endif
// Convenience macro to test if the logging is enabled on the specified level for given tags.
@@ -120,15 +120,17 @@
ATTRIBUTE_PRINTF(1, 0)
static void vwrite(const char* fmt, va_list args) {
char buf[LogBufferSize];
+ va_list saved_args; // For re-format on buf overflow.
+ va_copy(saved_args, args);
size_t prefix_len = LogPrefix<T0, T1, T2, T3, T4>::prefix(buf, sizeof(buf));
// Check that string fits in buffer; resize buffer if necessary
int ret = os::log_vsnprintf(buf + prefix_len, sizeof(buf) - prefix_len, fmt, args);
assert(ret >= 0, "Log message buffer issue");
- if ((size_t)ret > sizeof(buf)) {
+ if ((size_t)ret >= sizeof(buf)) {
size_t newbuf_len = prefix_len + ret + 1;
char* newbuf = NEW_C_HEAP_ARRAY(char, newbuf_len, mtLogging);
prefix_len = LogPrefix<T0, T1, T2, T3, T4>::prefix(newbuf, newbuf_len);
- ret = os::log_vsnprintf(newbuf + prefix_len, newbuf_len - prefix_len, fmt, args);
+ ret = os::log_vsnprintf(newbuf + prefix_len, newbuf_len - prefix_len, fmt, saved_args);
assert(ret >= 0, "Log message buffer issue");
puts<Level>(newbuf);
FREE_C_HEAP_ARRAY(char, newbuf);
--- a/hotspot/src/share/vm/logging/logFileStreamOutput.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/logging/logFileStreamOutput.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -40,7 +40,6 @@
for (size_t i = 0; i < LogDecorators::Count; i++) {
_decorator_padding[i] = 0;
}
- _decorator_padding[LogDecorators::level_decorator] = 7;
}
public:
--- a/hotspot/src/share/vm/logging/logPrefix.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/logging/logPrefix.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -43,6 +43,7 @@
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, age)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, alloc)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, barrier)) \
+ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, classhisto)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, compaction)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, compaction, phases)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, cpu)) \
--- a/hotspot/src/share/vm/logging/logTag.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/logging/logTag.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -39,7 +39,9 @@
LOG_TAG(classhisto) \
LOG_TAG(classresolve) \
LOG_TAG(classinit) \
- LOG_TAG(comp) \
+ LOG_TAG(classload) /* Trace all classes loaded */ \
+ LOG_TAG(classloaderdata) /* class loader loader_data lifetime */ \
+ LOG_TAG(classunload) /* Trace unloading of classes */ \
LOG_TAG(compaction) \
LOG_TAG(cpu) \
LOG_TAG(cset) \
@@ -59,6 +61,7 @@
LOG_TAG(marking) \
LOG_TAG(metaspace) \
LOG_TAG(monitorinflation) \
+ LOG_TAG(os) \
LOG_TAG(phases) \
LOG_TAG(plab) \
LOG_TAG(promotion) \
@@ -66,7 +69,6 @@
LOG_TAG(refine) \
LOG_TAG(region) \
LOG_TAG(remset) \
- LOG_TAG(rt) \
LOG_TAG(safepoint) \
LOG_TAG(scavenge) \
LOG_TAG(scrub) \
@@ -75,7 +77,6 @@
LOG_TAG(stats) \
LOG_TAG(stringdedup) \
LOG_TAG(survivor) \
- LOG_TAG(svc) \
LOG_TAG(sweep) \
LOG_TAG(task) \
LOG_TAG(tlab) \
--- a/hotspot/src/share/vm/logging/logTagLevelExpression.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/logging/logTagLevelExpression.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -29,21 +29,8 @@
const char* LogTagLevelExpression::DefaultExpressionString = "all";
-void LogTagLevelExpression::clear() {
- _ntags = 0;
- _ncombinations = 0;
- for (size_t combination = 0; combination < MaxCombinations; combination++) {
- _level[combination] = LogLevel::Invalid;
- _allow_other_tags[combination] = false;
- for (size_t tag = 0; tag < LogTag::MaxTags; tag++) {
- _tags[combination][tag] = LogTag::__NO_TAG;
- }
- }
-}
-
bool LogTagLevelExpression::parse(const char* str, outputStream* errstream) {
bool success = true;
- clear();
if (str == NULL || strcmp(str, "") == 0) {
str = DefaultExpressionString;
}
--- a/hotspot/src/share/vm/logging/logTagLevelExpression.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/logging/logTagLevelExpression.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -47,6 +47,11 @@
bool _allow_other_tags[MaxCombinations];
void new_combination() {
+ // Make sure either all tags are set or the last tag is __NO_TAG
+ if (_ntags < LogTag::MaxTags) {
+ _tags[_ncombinations][_ntags] = LogTag::__NO_TAG;
+ }
+
_ncombinations++;
_ntags = 0;
}
@@ -64,10 +69,13 @@
_allow_other_tags[_ncombinations] = true;
}
- void clear();
-
public:
LogTagLevelExpression() : _ntags(0), _ncombinations(0) {
+ for (size_t combination = 0; combination < MaxCombinations; combination++) {
+ _level[combination] = LogLevel::Invalid;
+ _allow_other_tags[combination] = false;
+ _tags[combination][0] = LogTag::__NO_TAG;
+ }
}
bool parse(const char* str, outputStream* errstream = NULL);
--- a/hotspot/src/share/vm/memory/filemap.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/memory/filemap.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -208,7 +208,7 @@
count ++;
bytes += (int)entry_size;
bytes += name_bytes;
- if (TraceClassPaths || (TraceClassLoading && Verbose)) {
+ if (TraceClassPaths) {
tty->print_cr("[Add main shared path (%s) %s]", (cpe->is_jar_file() ? "jar" : "dir"), name);
}
} else {
@@ -275,7 +275,7 @@
struct stat st;
const char* name = ent->_name;
bool ok = true;
- if (TraceClassPaths || (TraceClassLoading && Verbose)) {
+ if (TraceClassPaths) {
tty->print_cr("[Checking shared classpath entry: %s]", name);
}
if (os::stat(name, &st) != 0) {
@@ -301,7 +301,7 @@
}
}
if (ok) {
- if (TraceClassPaths || (TraceClassLoading && Verbose)) {
+ if (TraceClassPaths) {
tty->print_cr("[ok]");
}
} else if (!PrintSharedArchiveAndExit) {
--- a/hotspot/src/share/vm/memory/heapInspection.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/memory/heapInspection.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -40,6 +40,14 @@
// HeapInspection
+int KlassSizeStats::count(oop x) {
+ return (HeapWordSize * (((x) != NULL) ? (x)->size() : 0));
+}
+
+int KlassSizeStats::count_array(objArrayOop x) {
+ return (HeapWordSize * (((x) != NULL) ? (x)->size() : 0));
+}
+
inline KlassInfoEntry::~KlassInfoEntry() {
if (_subclasses != NULL) {
delete _subclasses;
@@ -218,9 +226,8 @@
return (*e1)->compare(*e1,*e2);
}
-KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit, const char* title) :
- _cit(cit),
- _title(title) {
+KlassInfoHisto::KlassInfoHisto(KlassInfoTable* cit) :
+ _cit(cit) {
_elements = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<KlassInfoEntry*>(_histo_initial_size, true);
}
@@ -640,7 +647,8 @@
if (print_stats) {
print_class_stats(st, csv_format, columns);
} else {
- st->print_cr("%s",title());
+ st->print_cr(" num #instances #bytes class name");
+ st->print_cr("----------------------------------------------");
print_elements(st);
}
}
@@ -721,10 +729,7 @@
}
// Sort and print klass instance info
- const char *title = "\n"
- " num #instances #bytes class name\n"
- "----------------------------------------------";
- KlassInfoHisto histo(&cit, title);
+ KlassInfoHisto histo(&cit);
HistoClosure hc(&histo);
cit.iterate(&hc);
--- a/hotspot/src/share/vm/memory/heapInspection.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/memory/heapInspection.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -154,13 +154,9 @@
HEAP_INSPECTION_COLUMNS_DO(DECLARE_KLASS_SIZE_STATS_FIELD)
- static int count(oop x) {
- return (HeapWordSize * (((x) != NULL) ? (x)->size() : 0));
- }
+ static int count(oop x);
- static int count_array(objArrayOop x) {
- return (HeapWordSize * (((x) != NULL) ? (x)->size() : 0));
- }
+ static int count_array(objArrayOop x);
template <class T> static int count(T* x) {
return (HeapWordSize * ((x) ? (x)->size() : 0));
@@ -285,8 +281,6 @@
KlassInfoTable *_cit;
GrowableArray<KlassInfoEntry*>* _elements;
GrowableArray<KlassInfoEntry*>* elements() const { return _elements; }
- const char* _title;
- const char* title() const { return _title; }
static int sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2);
void print_elements(outputStream* st) const;
void print_class_stats(outputStream* st, bool csv_format, const char *columns);
@@ -344,7 +338,7 @@
}
public:
- KlassInfoHisto(KlassInfoTable* cit, const char* title);
+ KlassInfoHisto(KlassInfoTable* cit);
~KlassInfoHisto();
void add(KlassInfoEntry* cie);
void print_histo_on(outputStream* st, bool print_class_stats, bool csv_format, const char *columns);
--- a/hotspot/src/share/vm/memory/metaspace.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -1234,7 +1234,7 @@
#ifdef ASSERT
new_entry->mangle();
#endif
- if (develop_log_is_enabled(Trace, gc, metaspace)) {
+ if (log_is_enabled(Trace, gc, metaspace)) {
LogHandle(gc, metaspace) log;
VirtualSpaceNode* vsl = current_virtual_space();
ResourceMark rm;
@@ -3051,7 +3051,7 @@
initialize_class_space(metaspace_rs);
- if (develop_log_is_enabled(Trace, gc, metaspace)) {
+ if (log_is_enabled(Trace, gc, metaspace)) {
LogHandle(gc, metaspace) log;
ResourceMark rm;
print_compressed_class_space(log.trace_stream(), requested_addr);
@@ -3474,7 +3474,7 @@
}
// Zero initialize.
- Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0);
+ Copy::fill_to_words((HeapWord*)result, word_size, 0);
return result;
}
@@ -3513,7 +3513,7 @@
}
// Zero initialize.
- Copy::fill_to_aligned_words((HeapWord*)result, word_size, 0);
+ Copy::fill_to_words((HeapWord*)result, word_size, 0);
return result;
}
@@ -3583,7 +3583,7 @@
void Metaspace::record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size) {
assert(DumpSharedSpaces, "sanity");
- int byte_size = (int)word_size * HeapWordSize;
+ int byte_size = (int)word_size * wordSize;
AllocRecord *rec = new AllocRecord((address)ptr, type, byte_size);
if (_alloc_record_head == NULL) {
@@ -3623,7 +3623,7 @@
for (AllocRecord *rec = _alloc_record_head; rec; rec = rec->_next) {
if (rec->_ptr == ptr) {
- assert(rec->_byte_size == (int)word_size * HeapWordSize, "sanity");
+ assert(rec->_byte_size == (int)word_size * wordSize, "sanity");
rec->_type = MetaspaceObj::DeallocatedType;
return;
}
--- a/hotspot/src/share/vm/memory/padded.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/memory/padded.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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
@@ -41,7 +41,7 @@
void* chunk = AllocateHeap(length * sizeof(PaddedEnd<T, alignment>) + alignment, flags);
// Make the initial alignment.
- PaddedEnd<T>* aligned_padded_array = (PaddedEnd<T>*)align_pointer_up(chunk, alignment);
+ PaddedEnd<T>* aligned_padded_array = (PaddedEnd<T>*)align_ptr_up(chunk, alignment);
// Call the default constructor for each element.
for (uint i = 0; i < length; i++) {
@@ -65,7 +65,7 @@
// Clear the allocated memory.
memset(chunk, 0, total_size);
// Align the chunk of memory.
- T** result = (T**)align_pointer_up(chunk, alignment);
+ T** result = (T**)align_ptr_up(chunk, alignment);
void* data_start = (void*)((uintptr_t)result + table_size);
// Fill in the row table.
@@ -87,7 +87,7 @@
memset(chunk, 0, length * sizeof(T) + alignment);
- return (T*)align_pointer_up(chunk, alignment);
+ return (T*)align_ptr_up(chunk, alignment);
}
#endif // SHARE_VM_MEMORY_PADDED_INLINE_HPP
--- a/hotspot/src/share/vm/memory/virtualspace.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/memory/virtualspace.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -502,7 +502,7 @@
// Calc address range within we try to attach (range of possible start addresses).
char* const highest_start = (char *)align_ptr_down((char *)UnscaledOopHeapMax - size, attach_point_alignment);
- char* const lowest_start = (char *)align_ptr_up ( aligned_heap_base_min_address , attach_point_alignment);
+ char* const lowest_start = (char *)align_ptr_up(aligned_heap_base_min_address, attach_point_alignment);
try_reserve_range(highest_start, lowest_start, attach_point_alignment,
aligned_heap_base_min_address, (char *)UnscaledOopHeapMax, size, alignment, large);
}
--- a/hotspot/src/share/vm/oops/arrayKlass.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/arrayKlass.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -42,12 +42,8 @@
// If this assert fails, see comments in base_create_array_klass.
header_size = InstanceKlass::header_size();
int vtable_len = Universe::base_vtable_size();
-#ifdef _LP64
- int size = header_size + align_object_offset(vtable_len);
-#else
int size = header_size + vtable_len;
-#endif
- return align_object_size(size);
+ return align_metadata_size(size);
}
@@ -85,10 +81,10 @@
ArrayKlass::ArrayKlass(Symbol* name) :
_dimension(1),
_higher_dimension(NULL),
- _lower_dimension(NULL),
- // Arrays don't add any new methods, so their vtable is the same size as
- // the vtable of klass Object.
- _vtable_len(Universe::base_vtable_size()) {
+ _lower_dimension(NULL) {
+ // Arrays don't add any new methods, so their vtable is the same size as
+ // the vtable of klass Object.
+ set_vtable_length(Universe::base_vtable_size());
set_name(name);
set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass());
set_layout_helper(Klass::_lh_neutral_value);
@@ -121,19 +117,6 @@
|| k == SystemDictionary::Serializable_klass();
}
-
-inline intptr_t* ArrayKlass::start_of_vtable() const {
- // all vtables start at the same place, that's why we use InstanceKlass::header_size here
- return ((intptr_t*)this) + InstanceKlass::header_size();
-}
-
-
-klassVtable* ArrayKlass::vtable() const {
- KlassHandle kh(Thread::current(), this);
- return new klassVtable(kh, start_of_vtable(), vtable_length() / vtableEntry::size());
-}
-
-
objArrayOop ArrayKlass::allocate_arrayArray(int n, int length, TRAPS) {
if (length < 0) {
THROW_0(vmSymbols::java_lang_NegativeArraySizeException());
--- a/hotspot/src/share/vm/oops/arrayKlass.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/arrayKlass.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -39,7 +39,6 @@
int _dimension; // This is n'th-dimensional array.
Klass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present).
Klass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present).
- int _vtable_len; // size of vtable for this klass
protected:
// Constructors
@@ -99,7 +98,6 @@
bool compute_is_subtype_of(Klass* k);
// Sizing
- static int header_size() { return sizeof(ArrayKlass)/HeapWordSize; }
static int static_size(int header_size);
#if INCLUDE_SERVICES
@@ -110,15 +108,6 @@
}
#endif
- // Java vtable
- klassVtable* vtable() const; // return new klassVtable
- int vtable_length() const { return _vtable_len; }
- static int base_vtable_length() { return Universe::base_vtable_size(); }
- void set_vtable_length(int len) { assert(len == base_vtable_length(), "bad length"); _vtable_len = len; }
- protected:
- inline intptr_t* start_of_vtable() const;
-
- public:
// Iterators
void array_klasses_do(void f(Klass* k));
void array_klasses_do(void f(Klass* k, TRAPS), TRAPS);
--- a/hotspot/src/share/vm/oops/constMethod.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/constMethod.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -144,7 +144,7 @@
int extra_words = align_size_up(extra_bytes, BytesPerWord) / BytesPerWord;
assert(extra_words == extra_bytes/BytesPerWord, "should already be aligned");
- return align_object_size(header_size() + extra_words);
+ return align_metadata_size(header_size() + extra_words);
}
Method* ConstMethod::method() const {
@@ -492,6 +492,6 @@
uncompressed_table_start = (u2*) m_end;
}
int gap = (intptr_t) uncompressed_table_start - (intptr_t) compressed_table_end;
- int max_gap = align_object_size(1)*BytesPerWord;
+ int max_gap = align_metadata_size(1)*BytesPerWord;
guarantee(gap >= 0 && gap < max_gap, "invalid method layout");
}
--- a/hotspot/src/share/vm/oops/constMethod.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/constMethod.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -328,9 +328,7 @@
}
// Sizing
- static int header_size() {
- return sizeof(ConstMethod)/HeapWordSize;
- }
+ static int header_size() { return sizeof(ConstMethod)/wordSize; }
// Size needed
static int size(int code_size, InlineTableSizes* sizes);
--- a/hotspot/src/share/vm/oops/constantPool.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/constantPool.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -723,8 +723,8 @@
}
// Sizing (in words)
- static int header_size() { return sizeof(ConstantPool)/HeapWordSize; }
- static int size(int length) { return align_object_size(header_size() + length); }
+ static int header_size() { return sizeof(ConstantPool)/wordSize; }
+ static int size(int length) { return align_metadata_size(header_size() + length); }
int size() const { return size(length()); }
#if INCLUDE_SERVICES
void collect_statistics(KlassSizeStats *sz) const;
--- a/hotspot/src/share/vm/oops/cpCache.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/cpCache.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, 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
@@ -396,9 +396,7 @@
int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index());
if (cpool->tag_at(holder_index).is_klass()) {
Klass* klass = cpool->resolved_klass_at(holder_index);
- if (!klass->is_instance_klass())
- klass = SystemDictionary::Object_klass();
- return InstanceKlass::cast(klass)->method_at_vtable(f2_as_index());
+ return klass->method_at_vtable(f2_as_index());
}
}
break;
--- a/hotspot/src/share/vm/oops/cpCache.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/cpCache.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, 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
@@ -364,7 +364,7 @@
return (TosState)((_flags >> tos_state_shift) & tos_state_mask); }
// Code generation support
- static WordSize size() { return in_WordSize(sizeof(ConstantPoolCacheEntry) / HeapWordSize); }
+ static WordSize size() { return in_WordSize(sizeof(ConstantPoolCacheEntry) / wordSize); }
static ByteSize size_in_bytes() { return in_ByteSize(sizeof(ConstantPoolCacheEntry)); }
static ByteSize indices_offset() { return byte_offset_of(ConstantPoolCacheEntry, _indices); }
static ByteSize f1_offset() { return byte_offset_of(ConstantPoolCacheEntry, _f1); }
@@ -439,14 +439,14 @@
private:
void set_length(int length) { _length = length; }
- static int header_size() { return sizeof(ConstantPoolCache) / HeapWordSize; }
- static int size(int length) { return align_object_size(header_size() + length * in_words(ConstantPoolCacheEntry::size())); }
+ static int header_size() { return sizeof(ConstantPoolCache) / wordSize; }
+ static int size(int length) { return align_metadata_size(header_size() + length * in_words(ConstantPoolCacheEntry::size())); }
public:
int size() const { return size(length()); }
private:
// Helpers
- ConstantPool** constant_pool_addr() { return &_constant_pool; }
+ ConstantPool** constant_pool_addr() { return &_constant_pool; }
ConstantPoolCacheEntry* base() const { return (ConstantPoolCacheEntry*)((address)this + in_bytes(base_offset())); }
friend class constantPoolCacheKlass;
--- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -55,7 +55,7 @@
void oop_ps_push_contents( oop obj, PSPromotionManager* pm);
// Parallel Compact
void oop_pc_follow_contents(oop obj, ParCompactionManager* cm);
- void oop_pc_update_pointers(oop obj);
+ void oop_pc_update_pointers(oop obj, ParCompactionManager* cm);
#endif
// Oop fields (and metadata) iterators
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/classFileParser.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verifier.hpp"
@@ -35,6 +36,7 @@
#include "interpreter/oopMapCache.hpp"
#include "interpreter/rewriter.hpp"
#include "jvmtifiles/jvmti.h"
+#include "logging/log.hpp"
#include "memory/heapInspection.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/metadataFactory.hpp"
@@ -211,9 +213,9 @@
InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind) :
_static_field_size(parser.static_field_size()),
_nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
- _vtable_len(parser.vtable_size()),
_itable_len(parser.itable_size()),
_reference_type(parser.reference_type()) {
+ set_vtable_length(parser.vtable_size());
set_kind(kind);
set_access_flags(parser.access_flags());
set_is_anonymous(parser.is_anonymous());
@@ -364,10 +366,6 @@
return !is_initialized();
}
-klassVtable* InstanceKlass::vtable() const {
- return new klassVtable(this, start_of_vtable(), vtable_length() / vtableEntry::size());
-}
-
klassItable* InstanceKlass::itable() const {
return new klassItable(instanceKlassHandle(this));
}
@@ -2667,6 +2665,10 @@
}
}
+static void print_vtable(vtableEntry* start, int len, outputStream* st) {
+ return print_vtable(reinterpret_cast<intptr_t*>(start), len, st);
+}
+
void InstanceKlass::print_on(outputStream* st) const {
assert(is_klass(), "must be klass");
Klass::print_on(st);
@@ -2904,18 +2906,88 @@
return external_name();
}
+void InstanceKlass::print_loading_log(LogLevel::type type,
+ ClassLoaderData* loader_data,
+ const ClassFileStream* cfs) const {
+ ResourceMark rm;
+ outputStream* log;
+
+ assert(type == LogLevel::Info || type == LogLevel::Debug, "sanity");
+
+ if (type == LogLevel::Info) {
+ log = LogHandle(classload)::info_stream();
+ } else {
+ assert(type == LogLevel::Debug,
+ "print_loading_log supports only Debug and Info levels");
+ log = LogHandle(classload)::debug_stream();
+ }
+
+ // Name and class hierarchy info
+ log->print("%s", external_name());
+
+ // Source
+ if (cfs != NULL) {
+ if (cfs->source() != NULL) {
+ log->print(" source: %s", cfs->source());
+ } else if (loader_data == ClassLoaderData::the_null_class_loader_data()) {
+ Thread* THREAD = Thread::current();
+ Klass* caller =
+ THREAD->is_Java_thread()
+ ? ((JavaThread*)THREAD)->security_get_caller_class(1)
+ : NULL;
+ // caller can be NULL, for example, during a JVMTI VM_Init hook
+ if (caller != NULL) {
+ log->print(" source: instance of %s", caller->external_name());
+ } else {
+ // source is unknown
+ }
+ } else {
+ Handle class_loader(loader_data->class_loader());
+ log->print(" source: %s", class_loader->klass()->external_name());
+ }
+ } else {
+ log->print(" source: shared objects file");
+ }
+
+ if (type == LogLevel::Debug) {
+ // Class hierarchy info
+ log->print(" klass: " INTPTR_FORMAT " super: " INTPTR_FORMAT,
+ p2i(this), p2i(superklass()));
+
+ if (local_interfaces() != NULL && local_interfaces()->length() > 0) {
+ log->print(" interfaces:");
+ int length = local_interfaces()->length();
+ for (int i = 0; i < length; i++) {
+ log->print(" " INTPTR_FORMAT,
+ p2i(InstanceKlass::cast(local_interfaces()->at(i))));
+ }
+ }
+
+ // Class loader
+ log->print(" loader: [");
+ loader_data->print_value_on(log);
+ log->print("]");
+
+ // Classfile checksum
+ if (cfs) {
+ log->print(" bytes: %d checksum: %08x",
+ cfs->length(),
+ ClassLoader::crc32(0, (const char*)cfs->buffer(),
+ cfs->length()));
+ }
+ }
+ log->cr();
+}
+
#if INCLUDE_SERVICES
// Size Statistics
void InstanceKlass::collect_statistics(KlassSizeStats *sz) const {
Klass::collect_statistics(sz);
- sz->_inst_size = HeapWordSize * size_helper();
- sz->_vtab_bytes = HeapWordSize * align_object_offset(vtable_length());
- sz->_itab_bytes = HeapWordSize * align_object_offset(itable_length());
- sz->_nonstatic_oopmap_bytes = HeapWordSize *
- ((is_interface() || is_anonymous()) ?
- align_object_offset(nonstatic_oop_map_size()) :
- nonstatic_oop_map_size());
+ sz->_inst_size = wordSize * size_helper();
+ sz->_vtab_bytes = wordSize * vtable_length();
+ sz->_itab_bytes = wordSize * itable_length();
+ sz->_nonstatic_oopmap_bytes = wordSize * nonstatic_oop_map_size();
int n = 0;
n += (sz->_methods_array_bytes = sz->count_array(methods()));
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -27,6 +27,7 @@
#include "classfile/classLoaderData.hpp"
#include "gc/shared/specialized_oop_closures.hpp"
+#include "logging/logLevel.hpp"
#include "memory/referenceType.hpp"
#include "oops/annotations.hpp"
#include "oops/constMethod.hpp"
@@ -94,10 +95,10 @@
uint count() const { return _count; }
void set_count(uint count) { _count = count; }
- // sizeof(OopMapBlock) in HeapWords.
+ // sizeof(OopMapBlock) in words.
static const int size_in_words() {
- return align_size_up(int(sizeof(OopMapBlock)), HeapWordSize) >>
- LogHeapWordSize;
+ return align_size_up(int(sizeof(OopMapBlock)), wordSize) >>
+ LogBytesPerWord;
}
private:
@@ -178,6 +179,7 @@
u2 _java_fields_count; // The number of declared Java fields
int _nonstatic_oop_map_size;// size in words of nonstatic oop map blocks
+ int _itable_len; // length of Java itable (in words)
// _is_marked_dependent can be set concurrently, thus cannot be part of the
// _misc_flags.
bool _is_marked_dependent; // used for marking during flushing and deoptimization
@@ -211,8 +213,6 @@
u2 _minor_version; // minor version number of class file
u2 _major_version; // major version number of class file
Thread* _init_thread; // Pointer to current thread doing initialization (to handle recusive initialization)
- int _vtable_len; // length of Java vtable (in words)
- int _itable_len; // length of Java itable (in words)
OopMapCache* volatile _oop_map_cache; // OopMapCache for all methods in the klass (allocated lazily)
MemberNameTable* _member_names; // Member names
JNIid* _jni_ids; // First JNI identifier for static fields in this class
@@ -311,10 +311,6 @@
int static_oop_field_count() const { return (int)_static_oop_field_count; }
void set_static_oop_field_count(u2 size) { _static_oop_field_count = size; }
- // Java vtable
- int vtable_length() const { return _vtable_len; }
- void set_vtable_length(int len) { _vtable_len = len; }
-
// Java itable
int itable_length() const { return _itable_len; }
void set_itable_length(int len) { _itable_len = len; }
@@ -927,19 +923,17 @@
}
// Sizing (in words)
- static int header_size() { return align_object_offset(sizeof(InstanceKlass)/HeapWordSize); }
+ static int header_size() { return sizeof(InstanceKlass)/wordSize; }
static int size(int vtable_length, int itable_length,
int nonstatic_oop_map_size,
bool is_interface, bool is_anonymous) {
- return align_object_size(header_size() +
- align_object_offset(vtable_length) +
- align_object_offset(itable_length) +
- ((is_interface || is_anonymous) ?
- align_object_offset(nonstatic_oop_map_size) :
- nonstatic_oop_map_size) +
- (is_interface ? (int)sizeof(Klass*)/HeapWordSize : 0) +
- (is_anonymous ? (int)sizeof(Klass*)/HeapWordSize : 0));
+ return align_metadata_size(header_size() +
+ vtable_length +
+ itable_length +
+ nonstatic_oop_map_size +
+ (is_interface ? (int)sizeof(Klass*)/wordSize : 0) +
+ (is_anonymous ? (int)sizeof(Klass*)/wordSize : 0));
}
int size() const { return size(vtable_length(),
itable_length(),
@@ -951,19 +945,15 @@
virtual void collect_statistics(KlassSizeStats *sz) const;
#endif
- static int vtable_start_offset() { return header_size(); }
- static int vtable_length_offset() { return offset_of(InstanceKlass, _vtable_len) / HeapWordSize; }
+ intptr_t* start_of_itable() const { return (intptr_t*)start_of_vtable() + vtable_length(); }
+ intptr_t* end_of_itable() const { return start_of_itable() + itable_length(); }
- intptr_t* start_of_vtable() const { return ((intptr_t*)this) + vtable_start_offset(); }
- intptr_t* start_of_itable() const { return start_of_vtable() + align_object_offset(vtable_length()); }
int itable_offset_in_words() const { return start_of_itable() - (intptr_t*)this; }
- intptr_t* end_of_itable() const { return start_of_itable() + itable_length(); }
-
address static_field_addr(int offset);
OopMapBlock* start_of_nonstatic_oop_maps() const {
- return (OopMapBlock*)(start_of_itable() + align_object_offset(itable_length()));
+ return (OopMapBlock*)(start_of_itable() + itable_length());
}
Klass** end_of_nonstatic_oop_maps() const {
@@ -1007,9 +997,7 @@
return !layout_helper_needs_slow_path(layout_helper());
}
- // Java vtable/itable
- klassVtable* vtable() const; // return new klassVtable wrapper
- inline Method* method_at_vtable(int index);
+ // Java itable
klassItable* itable() const; // return new klassItable wrapper
Method* method_at_itable(Klass* holder, int index, TRAPS);
@@ -1052,7 +1040,7 @@
void oop_ps_push_contents( oop obj, PSPromotionManager* pm);
// Parallel Compact
void oop_pc_follow_contents(oop obj, ParCompactionManager* cm);
- void oop_pc_update_pointers(oop obj);
+ void oop_pc_update_pointers(oop obj, ParCompactionManager* cm);
#endif
// Oop fields (and metadata) iterators
@@ -1257,19 +1245,11 @@
void verify_on(outputStream* st);
void oop_verify_on(oop obj, outputStream* st);
+
+ // Logging
+ void print_loading_log(LogLevel::type type, ClassLoaderData* loader_data, const ClassFileStream* cfs) const;
};
-inline Method* InstanceKlass::method_at_vtable(int index) {
-#ifndef PRODUCT
- assert(index >= 0, "valid vtable index");
- if (DebugVtables) {
- verify_vtable_index(index);
- }
-#endif
- vtableEntry* ve = (vtableEntry*)start_of_vtable();
- return ve[index].method();
-}
-
// for adding methods
// UNSET_IDNUM return means no more ids available
inline u2 InstanceKlass::next_method_idnum() {
--- a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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,7 +96,7 @@
void oop_ps_push_contents( oop obj, PSPromotionManager* pm);
// Parallel Compact
void oop_pc_follow_contents(oop obj, ParCompactionManager* cm);
- void oop_pc_update_pointers(oop obj);
+ void oop_pc_update_pointers(oop obj, ParCompactionManager* cm);
#endif
// Oop fields (and metadata) iterators
--- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -65,7 +65,7 @@
void oop_ps_push_contents( oop obj, PSPromotionManager* pm);
// Parallel Compact
void oop_pc_follow_contents(oop obj, ParCompactionManager* cm);
- void oop_pc_update_pointers(oop obj);
+ void oop_pc_update_pointers(oop obj, ParCompactionManager* cm);
#endif
// Oop fields (and metadata) iterators
--- a/hotspot/src/share/vm/oops/klass.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/klass.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -28,6 +28,7 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
+#include "logging/log.hpp"
#include "memory/heapInspection.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/oopFactory.hpp"
@@ -400,9 +401,9 @@
Klass* sub = current->subklass();
while (sub != NULL && !sub->is_loader_alive(is_alive)) {
#ifndef PRODUCT
- if (TraceClassUnloading && WizardMode) {
+ if (log_is_enabled(Trace, classunload)) {
ResourceMark rm;
- tty->print_cr("[Unlinking class (subclass) %s]", sub->external_name());
+ log_trace(classunload)("unlinking class (subclass): %s", sub->external_name());
}
#endif
sub = sub->next_sibling();
@@ -415,9 +416,9 @@
// Find and set the first alive sibling
Klass* sibling = current->next_sibling();
while (sibling != NULL && !sibling->is_loader_alive(is_alive)) {
- if (TraceClassUnloading && WizardMode) {
+ if (log_is_enabled(Trace, classunload)) {
ResourceMark rm;
- tty->print_cr("[Unlinking class (sibling) %s]", sibling->external_name());
+ log_trace(classunload)("[Unlinking class (sibling) %s]", sibling->external_name());
}
sibling = sibling->next_sibling();
}
@@ -673,6 +674,28 @@
guarantee(obj->klass()->is_klass(), "klass field is not a klass");
}
+klassVtable* Klass::vtable() const {
+ return new klassVtable(this, start_of_vtable(), vtable_length() / vtableEntry::size());
+}
+
+vtableEntry* Klass::start_of_vtable() const {
+ return (vtableEntry*) ((address)this + in_bytes(vtable_start_offset()));
+}
+
+Method* Klass::method_at_vtable(int index) {
+#ifndef PRODUCT
+ assert(index >= 0, "valid vtable index");
+ if (DebugVtables) {
+ verify_vtable_index(index);
+ }
+#endif
+ return start_of_vtable()[index].method();
+}
+
+ByteSize Klass::vtable_start_offset() {
+ return in_ByteSize(InstanceKlass::header_size() * wordSize);
+}
+
#ifndef PRODUCT
bool Klass::verify_vtable_index(int i) {
--- a/hotspot/src/share/vm/oops/klass.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/klass.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -57,6 +57,7 @@
class PSPromotionManager;
class KlassSizeStats;
class fieldDescriptor;
+class vtableEntry;
class Klass : public Metadata {
friend class VMStructs;
@@ -131,13 +132,16 @@
jint _modifier_flags; // Processed access flags, for use by Class.getModifiers.
AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here.
+ TRACE_DEFINE_KLASS_TRACE_ID;
+
// Biased locking implementation and statistics
// (the 64-bit chunk goes first, to avoid some fragmentation)
jlong _last_biased_lock_bulk_revocation_time;
markOop _prototype_header; // Used when biased locking is both enabled and disabled for this type
jint _biased_lock_revocation_count;
- TRACE_DEFINE_KLASS_TRACE_ID;
+ // vtable length
+ int _vtable_len;
// Remembered sets support for the oops in the klasses.
jbyte _modified_oops; // Card Table Equivalent (YC/CMS support)
@@ -352,13 +356,13 @@
| (log2_esize << _lh_log2_element_size_shift);
}
static jint instance_layout_helper(jint size, bool slow_path_flag) {
- return (size << LogHeapWordSize)
+ return (size << LogBytesPerWord)
| (slow_path_flag ? _lh_instance_slow_path_bit : 0);
}
static int layout_helper_to_size_helper(jint lh) {
assert(lh > (jint)_lh_neutral_value, "must be instance");
// Note that the following expression discards _lh_instance_slow_path_bit.
- return lh >> LogHeapWordSize;
+ return lh >> LogBytesPerWord;
}
// Out-of-line version computes everything based on the etype:
static jint array_layout_helper(BasicType etype);
@@ -374,8 +378,8 @@
#endif
// vtables
- virtual klassVtable* vtable() const = 0;
- virtual int vtable_length() const = 0;
+ klassVtable* vtable() const;
+ int vtable_length() const { return _vtable_len; }
// subclass check
bool is_subclass_of(const Klass* k) const;
@@ -438,7 +442,17 @@
virtual Klass* array_klass_impl(bool or_null, int rank, TRAPS);
virtual Klass* array_klass_impl(bool or_null, TRAPS);
+ void set_vtable_length(int len) { _vtable_len= len; }
+
+ vtableEntry* start_of_vtable() const;
public:
+ Method* method_at_vtable(int index);
+
+ static ByteSize vtable_start_offset();
+ static ByteSize vtable_length_offset() {
+ return byte_offset_of(Klass, _vtable_len);
+ }
+
// CDS support - remove and restore oops from metadata. Oops are not shared.
virtual void remove_unshareable_info();
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
@@ -579,7 +593,7 @@
virtual void oop_ps_push_contents( oop obj, PSPromotionManager* pm) = 0;
// Parallel Compact
virtual void oop_pc_follow_contents(oop obj, ParCompactionManager* cm) = 0;
- virtual void oop_pc_update_pointers(oop obj) = 0;
+ virtual void oop_pc_update_pointers(oop obj, ParCompactionManager* cm) = 0;
#endif
// Iterators specialized to particular subtypes
--- a/hotspot/src/share/vm/oops/klassVtable.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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,7 @@
superVtable->verify(tty, true);
#endif
superVtable->copy_vtable_to(table());
- if (develop_log_is_enabled(Trace, vtables)) {
+ if (log_develop_is_enabled(Trace, vtables)) {
ResourceMark rm;
log_develop_trace(vtables)("copy vtable from %s to %s size %d",
super->internal_name(), klass()->internal_name(),
@@ -272,7 +272,7 @@
assert(super_method->name() == name && super_method->signature() == signature, "vtable entry name/sig mismatch");
#endif
if (supersuperklass->is_override(super_method, target_loader, target_classname, THREAD)) {
- if (develop_log_is_enabled(Trace, vtables)) {
+ if (log_develop_is_enabled(Trace, vtables)) {
ResourceMark rm(THREAD);
outputStream* logst = LogHandle(vtables)::trace_stream();
char* sig = target_method()->name_and_sig_as_C_string();
@@ -303,7 +303,7 @@
KlassHandle target_klass, Method* super_method,
Thread* thread) {
#ifndef PRODUCT
- if (develop_log_is_enabled(Trace, vtables)) {
+ if (log_develop_is_enabled(Trace, vtables)) {
ResourceMark rm(thread);
outputStream* logst = LogHandle(vtables)::trace_stream();
char* sig = target_method()->name_and_sig_as_C_string();
@@ -491,7 +491,7 @@
}
void klassVtable::put_method_at(Method* m, int index) {
- if (develop_log_is_enabled(Trace, vtables)) {
+ if (log_develop_is_enabled(Trace, vtables)) {
ResourceMark rm;
outputStream* logst = LogHandle(vtables)::trace_stream();
const char* sig = (m != NULL) ? m->name_and_sig_as_C_string() : "<NULL>";
@@ -818,7 +818,7 @@
get_mirandas(&mirandas, NULL, ik()->super(), ik()->methods(),
ik()->default_methods(), ik()->local_interfaces());
for (int i = 0; i < mirandas.length(); i++) {
- if (develop_log_is_enabled(Trace, vtables)) {
+ if (log_develop_is_enabled(Trace, vtables)) {
Method* meth = mirandas.at(i);
ResourceMark rm(Thread::current());
outputStream* logst = LogHandle(vtables)::trace_stream();
@@ -1043,7 +1043,7 @@
if (interface_method_needs_itable_index(m)) {
assert(!m->is_final_method(), "no final interface methods");
// If m is already assigned a vtable index, do not disturb it.
- if (develop_log_is_enabled(Trace, itables)) {
+ if (log_develop_is_enabled(Trace, itables)) {
ResourceMark rm;
outputStream* logst = LogHandle(itables)::trace_stream();
assert(m != NULL, "methods can never be null");
@@ -1158,7 +1158,7 @@
int ime_num = m->itable_index();
assert(ime_num < ime_count, "oob");
itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target());
- if (develop_log_is_enabled(Trace, itables)) {
+ if (log_develop_is_enabled(Trace, itables)) {
ResourceMark rm(THREAD);
if (target() != NULL) {
outputStream* logst = LogHandle(itables)::trace_stream();
@@ -1331,7 +1331,7 @@
int itable_size = calc_itable_size(cic.nof_interfaces() + 1, cic.nof_methods());
// Statistics
- update_stats(itable_size * HeapWordSize);
+ update_stats(itable_size * wordSize);
return itable_size;
}
--- a/hotspot/src/share/vm/oops/klassVtable.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/klassVtable.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -170,9 +170,9 @@
public:
// size in words
- static int size() {
- return sizeof(vtableEntry) / sizeof(HeapWord);
- }
+ static int size() { return sizeof(vtableEntry) / wordSize; }
+ static int size_in_bytes() { return sizeof(vtableEntry); }
+
static int method_offset_in_bytes() { return offset_of(vtableEntry, _method); }
Method* method() const { return _method; }
@@ -223,7 +223,7 @@
void initialize(Klass* interf, int offset) { _interface = interf; _offset = offset; }
// Static size and offset accessors
- static int size() { return sizeof(itableOffsetEntry) / HeapWordSize; } // size in words
+ static int size() { return sizeof(itableOffsetEntry) / wordSize; } // size in words
static int interface_offset_in_bytes() { return offset_of(itableOffsetEntry, _interface); }
static int offset_offset_in_bytes() { return offset_of(itableOffsetEntry, _offset); }
@@ -243,7 +243,7 @@
void initialize(Method* method);
// Static size and offset accessors
- static int size() { return sizeof(itableMethodEntry) / HeapWordSize; } // size in words
+ static int size() { return sizeof(itableMethodEntry) / wordSize; } // size in words
static int method_offset_in_bytes() { return offset_of(itableMethodEntry, _method); }
friend class klassItable;
--- a/hotspot/src/share/vm/oops/markOop.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/markOop.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2016, 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,6 +27,7 @@
#include "oops/klass.hpp"
#include "oops/markOop.hpp"
+#include "oops/oop.inline.hpp"
#include "runtime/globals.hpp"
// Should this header be preserved during GC (when biased locking is enabled)?
--- a/hotspot/src/share/vm/oops/metadata.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/metadata.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -58,13 +58,13 @@
if (this == NULL)
st->print("NULL");
else
- print_on(tty);
+ print_on(st);
}
void print_value_on_maybe_null(outputStream* st) const {
if (this == NULL)
st->print("NULL");
else
- print_value_on(tty);
+ print_value_on(st);
}
virtual void print_on(outputStream* st) const; // First level print
--- a/hotspot/src/share/vm/oops/method.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/method.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -295,7 +295,7 @@
// If native, then include pointers for native_function and signature_handler
int extra_bytes = (is_native) ? 2*sizeof(address*) : 0;
int extra_words = align_size_up(extra_bytes, BytesPerWord) / BytesPerWord;
- return align_object_size(header_size() + extra_words);
+ return align_metadata_size(header_size() + extra_words);
}
@@ -2101,15 +2101,16 @@
Method m;
// This assumes that the vtbl pointer is the first word of a C++ object.
// This assumption is also in universe.cpp patch_klass_vtble
- void* vtbl2 = dereference_vptr((const void*)&m);
- void* this_vtbl = dereference_vptr(ptr);
- return vtbl2 == this_vtbl;
+ return dereference_vptr(&m) == dereference_vptr(ptr);
}
// Check that this pointer is valid by checking that the vtbl pointer matches
bool Method::is_valid_method() const {
if (this == NULL) {
return false;
+ } else if ((intptr_t(this) & (wordSize-1)) != 0) {
+ // Quick sanity check on pointer.
+ return false;
} else if (!is_metaspace_object()) {
return false;
} else {
--- a/hotspot/src/share/vm/oops/method.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/method.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -622,7 +622,7 @@
bool has_compiled_code() const { return code() != NULL; }
// sizing
- static int header_size() { return sizeof(Method)/HeapWordSize; }
+ static int header_size() { return sizeof(Method)/wordSize; }
static int size(bool is_native);
int size() const { return method_size(); }
#if INCLUDE_SERVICES
--- a/hotspot/src/share/vm/oops/methodData.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/methodData.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -934,7 +934,7 @@
int MethodData::compute_allocation_size_in_words(const methodHandle& method) {
int byte_size = compute_allocation_size_in_bytes(method);
int word_size = align_size_up(byte_size, BytesPerWord) / BytesPerWord;
- return align_object_size(word_size);
+ return align_metadata_size(word_size);
}
// Initialize an individual data segment. Returns the size of
--- a/hotspot/src/share/vm/oops/methodData.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/methodData.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2016, 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
@@ -2334,7 +2334,7 @@
// My size
int size_in_bytes() const { return _size; }
- int size() const { return align_object_size(align_size_up(_size, BytesPerWord)/BytesPerWord); }
+ int size() const { return align_metadata_size(align_size_up(_size, BytesPerWord)/BytesPerWord); }
#if INCLUDE_SERVICES
void collect_statistics(KlassSizeStats *sz) const;
#endif
--- a/hotspot/src/share/vm/oops/objArrayKlass.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -101,7 +101,7 @@
}
// Sizing
- static int header_size() { return sizeof(ObjArrayKlass)/HeapWordSize; }
+ static int header_size() { return sizeof(ObjArrayKlass)/wordSize; }
int size() const { return ArrayKlass::static_size(header_size()); }
// Initialization (virtual from Klass)
@@ -116,7 +116,7 @@
void oop_ps_push_contents( oop obj, PSPromotionManager* pm);
// Parallel Compact
void oop_pc_follow_contents(oop obj, ParCompactionManager* cm);
- void oop_pc_update_pointers(oop obj);
+ void oop_pc_update_pointers(oop obj, ParCompactionManager* cm);
#endif
// Oop fields (and metadata) iterators
--- a/hotspot/src/share/vm/oops/objArrayOop.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/objArrayOop.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -81,7 +81,7 @@
// Accessing
oop obj_at(int index) const;
- void /*inline*/ obj_at_put(int index, oop value);
+ void inline obj_at_put(int index, oop value);
oop atomic_compare_exchange_oop(int index, oop exchange_value, oop compare_value);
--- a/hotspot/src/share/vm/oops/objArrayOop.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/objArrayOop.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -39,7 +39,7 @@
}
}
-inline void objArrayOopDesc::obj_at_put(int index, oop value) {
+void objArrayOopDesc::obj_at_put(int index, oop value) {
if (UseCompressedOops) {
oop_store(obj_at_addr<narrowOop>(index), value);
} else {
--- a/hotspot/src/share/vm/oops/oop.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/oop.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -82,16 +82,16 @@
// objects during a GC) -- requires a valid klass pointer
inline void init_mark();
- /*inline*/ Klass* klass() const;
+ inline Klass* klass() const;
inline Klass* klass_or_null() const volatile;
inline Klass** klass_addr();
inline narrowKlass* compressed_klass_addr();
- /*inline*/ void set_klass(Klass* k);
+ inline void set_klass(Klass* k);
// For klass field compression
inline int klass_gap() const;
- /*inline*/ void set_klass_gap(int z);
+ inline void set_klass_gap(int z);
// For when the klass pointer is being used as a linked list "next" field.
inline void set_klass_to_list_ptr(oop k);
inline oop list_ptr_from_klass();
@@ -103,7 +103,7 @@
inline bool is_a(Klass* k) const;
// Returns the actual oop size of the object
- /*inline*/ int size();
+ inline int size();
// Sometimes (for complicated concurrency-related reasons), it is useful
// to be able to figure out the size of an object knowing its klass.
@@ -111,7 +111,7 @@
// type test operations (inlined in oop.inline.hpp)
inline bool is_instance() const;
- /*inline*/ bool is_array() const;
+ inline bool is_array() const;
inline bool is_objArray() const;
inline bool is_typeArray() const;
@@ -149,15 +149,15 @@
// These are overloaded for oop and narrowOop as are the other functions
// below so that they can be called in template functions.
static inline oop decode_heap_oop_not_null(oop v) { return v; }
- static /*inline*/ oop decode_heap_oop_not_null(narrowOop v);
+ static inline oop decode_heap_oop_not_null(narrowOop v);
static inline oop decode_heap_oop(oop v) { return v; }
- static /*inline*/ oop decode_heap_oop(narrowOop v);
+ static inline oop decode_heap_oop(narrowOop v);
// Encode an oop pointer to a narrow oop. The or_null versions accept
// null oop pointer, others do not in order to eliminate the
// null checking branches.
static inline narrowOop encode_heap_oop_not_null(oop v);
- static /*inline*/ narrowOop encode_heap_oop(oop v);
+ static inline narrowOop encode_heap_oop(oop v);
// Load an oop out of the Java heap as is without decoding.
// Called by GC to check for null before decoding.
@@ -284,8 +284,8 @@
inline bool has_bias_pattern() const;
// asserts
- /*inline*/ bool is_oop(bool ignore_mark_word = false) const;
- /*inline*/ bool is_oop_or_null(bool ignore_mark_word = false) const;
+ inline bool is_oop(bool ignore_mark_word = false) const;
+ inline bool is_oop_or_null(bool ignore_mark_word = false) const;
#ifndef PRODUCT
inline bool is_unlocked_oop() const;
#endif
@@ -312,7 +312,7 @@
inline oop forwardee() const;
// Age of object during scavenge
- /*inline*/ uint age() const;
+ inline uint age() const;
inline void incr_age();
// mark-sweep support
@@ -330,8 +330,8 @@
inline int ms_adjust_pointers();
#if INCLUDE_ALL_GCS
// Parallel Compact
- inline void pc_follow_contents(ParCompactionManager* pc);
- inline void pc_update_contents();
+ inline void pc_follow_contents(ParCompactionManager* cm);
+ inline void pc_update_contents(ParCompactionManager* cm);
// Parallel Scavenge
inline void ps_push_contents(PSPromotionManager* pm);
#endif
--- a/hotspot/src/share/vm/oops/oop.inline.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -100,7 +100,7 @@
set_mark(markOopDesc::prototype_for_object(this));
}
-inline Klass* oopDesc::klass() const {
+Klass* oopDesc::klass() const {
if (UseCompressedClassPointers) {
return Klass::decode_klass_not_null(_metadata._compressed_klass);
} else {
@@ -129,7 +129,7 @@
return &_metadata._compressed_klass;
}
-inline void oopDesc::set_klass(Klass* k) {
+void oopDesc::set_klass(Klass* k) {
// since klasses are promoted no store check is needed
assert(Universe::is_bootstrapping() || k != NULL, "must be a real Klass*");
assert(Universe::is_bootstrapping() || k->is_klass(), "not a Klass*");
@@ -144,7 +144,7 @@
return *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes());
}
-inline void oopDesc::set_klass_gap(int v) {
+void oopDesc::set_klass_gap(int v) {
if (UseCompressedClassPointers) {
*(int*)(((intptr_t)this) + klass_gap_offset_in_bytes()) = v;
}
@@ -174,7 +174,7 @@
return klass()->is_subtype_of(k);
}
-inline int oopDesc::size() {
+int oopDesc::size() {
return size_given_klass(klass());
}
@@ -264,7 +264,7 @@
}
bool oopDesc::is_instance() const { return klass()->is_instance_klass(); }
-inline bool oopDesc::is_array() const { return klass()->is_array_klass(); }
+bool oopDesc::is_array() const { return klass()->is_array_klass(); }
bool oopDesc::is_objArray() const { return klass()->is_objArray_klass(); }
bool oopDesc::is_typeArray() const { return klass()->is_typeArray_klass(); }
@@ -298,7 +298,7 @@
return cast_from_oop<intptr_t>(obj) % MinObjAlignmentInBytes == 0;
}
-inline oop oopDesc::decode_heap_oop_not_null(narrowOop v) {
+oop oopDesc::decode_heap_oop_not_null(narrowOop v) {
assert(!is_null(v), "narrow oop value can never be zero");
address base = Universe::narrow_oop_base();
int shift = Universe::narrow_oop_shift();
@@ -307,7 +307,7 @@
return result;
}
-inline oop oopDesc::decode_heap_oop(narrowOop v) {
+oop oopDesc::decode_heap_oop(narrowOop v) {
return is_null(v) ? (oop)NULL : decode_heap_oop_not_null(v);
}
@@ -325,7 +325,7 @@
return (narrowOop)result;
}
-inline narrowOop oopDesc::encode_heap_oop(oop v) {
+narrowOop oopDesc::encode_heap_oop(oop v) {
return (is_null(v)) ? (narrowOop)0 : encode_heap_oop_not_null(v);
}
@@ -516,7 +516,7 @@
}
// used only for asserts
-inline bool oopDesc::is_oop(bool ignore_mark_word) const {
+bool oopDesc::is_oop(bool ignore_mark_word) const {
oop obj = (oop) this;
if (!check_obj_alignment(obj)) return false;
if (!Universe::heap()->is_in_reserved(obj)) return false;
@@ -538,7 +538,7 @@
// used only for asserts
-inline bool oopDesc::is_oop_or_null(bool ignore_mark_word) const {
+bool oopDesc::is_oop_or_null(bool ignore_mark_word) const {
return this == NULL ? true : is_oop(ignore_mark_word);
}
@@ -620,7 +620,7 @@
}
// The following method needs to be MT safe.
-inline uint oopDesc::age() const {
+uint oopDesc::age() const {
assert(!is_forwarded(), "Attempt to read age from forwarded mark");
if (has_displaced_mark()) {
return displaced_mark()->age();
@@ -650,11 +650,11 @@
klass()->oop_pc_follow_contents(this, cm);
}
-void oopDesc::pc_update_contents() {
+void oopDesc::pc_update_contents(ParCompactionManager* cm) {
Klass* k = klass();
if (!k->is_typeArray_klass()) {
// It might contain oops beyond the header, so take the virtual call.
- k->oop_pc_update_pointers(this);
+ k->oop_pc_update_pointers(this, cm);
}
// Else skip it. The TypeArrayKlass in the header never needs scavenging.
}
--- a/hotspot/src/share/vm/oops/symbol.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/symbol.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -42,20 +42,19 @@
}
void* Symbol::operator new(size_t sz, int len, TRAPS) throw() {
- int alloc_size = size(len)*HeapWordSize;
+ int alloc_size = size(len)*wordSize;
address res = (address) AllocateHeap(alloc_size, mtSymbol);
return res;
}
void* Symbol::operator new(size_t sz, int len, Arena* arena, TRAPS) throw() {
- int alloc_size = size(len)*HeapWordSize;
- address res = (address)arena->Amalloc(alloc_size);
+ int alloc_size = size(len)*wordSize;
+ address res = (address)arena->Amalloc_4(alloc_size);
return res;
}
void* Symbol::operator new(size_t sz, int len, ClassLoaderData* loader_data, TRAPS) throw() {
address res;
- int alloc_size = size(len)*HeapWordSize;
res = (address) Metaspace::allocate(loader_data, size(len), true,
MetaspaceObj::SymbolType, CHECK_NULL);
return res;
--- a/hotspot/src/share/vm/oops/symbol.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/symbol.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -125,8 +125,8 @@
};
static int size(int length) {
- size_t sz = heap_word_size(sizeof(Symbol) + (length > 2 ? length - 2 : 0));
- return align_object_size(sz);
+ // minimum number of natural words needed to hold these bits (no non-heap version)
+ return (int)heap_word_size(sizeof(Symbol) + (length > 2 ? length - 2 : 0));
}
void byte_at_put(int index, int value) {
--- a/hotspot/src/share/vm/oops/typeArrayKlass.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/oops/typeArrayKlass.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -81,7 +81,7 @@
void oop_ps_push_contents( oop obj, PSPromotionManager* pm);
// Parallel Compact
void oop_pc_follow_contents(oop obj, ParCompactionManager* cm);
- void oop_pc_update_pointers(oop obj);
+ void oop_pc_update_pointers(oop obj, ParCompactionManager* cm);
#endif
// Oop iterators. Since there are no oops in TypeArrayKlasses,
@@ -133,7 +133,7 @@
static const char* external_name(BasicType type);
// Sizing
- static int header_size() { return sizeof(TypeArrayKlass)/HeapWordSize; }
+ static int header_size() { return sizeof(TypeArrayKlass)/wordSize; }
int size() const { return ArrayKlass::static_size(header_size()); }
// Initialization (virtual from Klass)
--- a/hotspot/src/share/vm/opto/callGenerator.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/opto/callGenerator.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -867,17 +867,18 @@
}
}
// Cast reference arguments to its type.
- for (int i = 0; i < signature->count(); i++) {
+ for (int i = 0, j = 0; i < signature->count(); i++) {
ciType* t = signature->type_at(i);
if (t->is_klass()) {
- Node* arg = kit.argument(receiver_skip + i);
+ Node* arg = kit.argument(receiver_skip + j);
const TypeOopPtr* arg_type = arg->bottom_type()->isa_oopptr();
const Type* sig_type = TypeOopPtr::make_from_klass(t->as_klass());
if (arg_type != NULL && !arg_type->higher_equal(sig_type)) {
Node* cast_obj = gvn.transform(new CheckCastPPNode(kit.control(), arg, sig_type));
- kit.set_argument(receiver_skip + i, cast_obj);
+ kit.set_argument(receiver_skip + j, cast_obj);
}
}
+ j += t->size(); // long and double take two slots
}
// Try to get the most accurate receiver type
--- a/hotspot/src/share/vm/opto/library_call.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -3822,8 +3822,8 @@
assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index,
"bad index %d", vtable_index);
// Get the Method* out of the appropriate vtable entry.
- int entry_offset = (InstanceKlass::vtable_start_offset() +
- vtable_index*vtableEntry::size()) * wordSize +
+ int entry_offset = in_bytes(Klass::vtable_start_offset()) +
+ vtable_index*vtableEntry::size_in_bytes() +
vtableEntry::method_offset_in_bytes();
Node* entry_addr = basic_plus_adr(obj_klass, entry_offset);
Node* target_call = make_load(NULL, entry_addr, TypePtr::NOTNULL, T_ADDRESS, MemNode::unordered);
--- a/hotspot/src/share/vm/opto/loopTransform.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/opto/loopTransform.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -2404,15 +2404,25 @@
if (needs_guard) {
// Check for an obvious zero trip guard.
Node* inctrl = PhaseIdealLoop::skip_loop_predicates(cl->in(LoopNode::EntryControl));
- if (inctrl->Opcode() == Op_IfTrue) {
+ if (inctrl->Opcode() == Op_IfTrue || inctrl->Opcode() == Op_IfFalse) {
+ bool maybe_swapped = (inctrl->Opcode() == Op_IfFalse);
// The test should look like just the backedge of a CountedLoop
Node* iff = inctrl->in(0);
if (iff->is_If()) {
Node* bol = iff->in(1);
- if (bol->is_Bool() && bol->as_Bool()->_test._test == cl->loopexit()->test_trip()) {
- Node* cmp = bol->in(1);
- if (cmp->is_Cmp() && cmp->in(1) == cl->init_trip() && cmp->in(2) == cl->limit()) {
- needs_guard = false;
+ if (bol->is_Bool()) {
+ BoolTest test = bol->as_Bool()->_test;
+ if (maybe_swapped) {
+ test._test = test.commute();
+ test._test = test.negate();
+ }
+ if (test._test == cl->loopexit()->test_trip()) {
+ Node* cmp = bol->in(1);
+ int init_idx = maybe_swapped ? 2 : 1;
+ int limit_idx = maybe_swapped ? 1 : 2;
+ if (cmp->is_Cmp() && cmp->in(init_idx) == cl->init_trip() && cmp->in(limit_idx) == cl->limit()) {
+ needs_guard = false;
+ }
}
}
}
--- a/hotspot/src/share/vm/prims/jni.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/prims/jni.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1131,11 +1131,7 @@
assert(m->valid_vtable_index(), "no valid vtable index");
int vtbl_index = m->vtable_index();
if (vtbl_index != Method::nonvirtual_vtable_index) {
- Klass* k = h_recv->klass();
- // k might be an arrayKlassOop but all vtables start at
- // the same place. The cast is to avoid virtual call and assertion.
- InstanceKlass *ik = (InstanceKlass*)k;
- selected_method = ik->method_at_vtable(vtbl_index);
+ selected_method = h_recv->klass()->method_at_vtable(vtbl_index);
} else {
// final method
selected_method = m;
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/interpreter.hpp"
#include "jvmtifiles/jvmtiEnv.hpp"
+#include "logging/log.hpp"
#include "logging/logConfiguration.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp"
@@ -473,9 +474,7 @@
ObjectLocker ol(loader_lock, thread);
// add the jar file to the bootclasspath
- if (TraceClassLoading) {
- tty->print_cr("[Opened %s]", zip_entry->name());
- }
+ log_info(classload)("opened: %s", zip_entry->name());
ClassLoaderExt::append_boot_classpath(zip_entry);
return JVMTI_ERROR_NONE;
} else {
@@ -625,8 +624,13 @@
// ignore
break;
case JVMTI_VERBOSE_CLASS:
- TraceClassLoading = value != 0;
- TraceClassUnloading = value != 0;
+ if (value == 0) {
+ LogConfiguration::parse_log_arguments("stdout", "classunload=off", NULL, NULL, NULL);
+ LogConfiguration::parse_log_arguments("stdout", "classload=off", NULL, NULL, NULL);
+ } else {
+ LogConfiguration::parse_log_arguments("stdout", "classload=info", NULL, NULL, NULL);
+ LogConfiguration::parse_log_arguments("stdout", "classunload=info", NULL, NULL, NULL);
+ }
break;
case JVMTI_VERBOSE_GC:
if (value == 0) {
--- a/hotspot/src/share/vm/prims/whitebox.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -51,9 +51,9 @@
#include "utilities/exceptions.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
-#include "gc/g1/concurrentMark.hpp"
#include "gc/g1/concurrentMarkThread.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1ConcurrentMark.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/parallel/parallelScavengeHeap.inline.hpp"
#include "gc/parallel/adjoiningGenerations.hpp"
@@ -1410,7 +1410,7 @@
if (res == NULL) {
tty->print_cr("Invalid layout of %s at %s", ik->external_name(),
name_symbol->as_C_string());
- vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
+ vm_exit_during_initialization("Invalid layout of preloaded class: use -Xlog:classload=info to see the origin of the problem class");
}
//fetch the field at the offset we've found
--- a/hotspot/src/share/vm/runtime/arguments.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -83,6 +83,7 @@
int Arguments::_num_jvm_args = 0;
char* Arguments::_java_command = NULL;
SystemProperty* Arguments::_system_properties = NULL;
+const char* Arguments::_gc_log_filename = NULL;
bool Arguments::_has_profile = false;
size_t Arguments::_conservative_max_heap_alignment = 0;
size_t Arguments::_min_heap_size = 0;
@@ -401,10 +402,12 @@
};
static AliasedLoggingFlag const aliased_logging_flags[] = {
- { "TraceClassResolution", LogLevel::Info, true, LogTag::_classresolve },
- { "TraceExceptions", LogLevel::Info, true, LogTag::_exceptions },
- { "TraceMonitorInflation", LogLevel::Debug, true, LogTag::_monitorinflation },
- { NULL, LogLevel::Off, false, LogTag::__NO_TAG }
+ { "TraceClassLoading", LogLevel::Info, true, LogTag::_classload },
+ { "TraceClassUnloading", LogLevel::Info, true, LogTag::_classunload },
+ { "TraceClassResolution", LogLevel::Info, true, LogTag::_classresolve },
+ { "TraceExceptions", LogLevel::Info, true, LogTag::_exceptions },
+ { "TraceMonitorInflation", LogLevel::Debug, true, LogTag::_monitorinflation },
+ { NULL, LogLevel::Off, false, LogTag::__NO_TAG }
};
// Return true if "v" is less than "other", where "other" may be "undefined".
@@ -2652,12 +2655,8 @@
// -verbose:[class/gc/jni]
if (match_option(option, "-verbose", &tail)) {
if (!strcmp(tail, ":class") || !strcmp(tail, "")) {
- if (FLAG_SET_CMDLINE(bool, TraceClassLoading, true) != Flag::SUCCESS) {
- return JNI_EINVAL;
- }
- if (FLAG_SET_CMDLINE(bool, TraceClassUnloading, true) != Flag::SUCCESS) {
- return JNI_EINVAL;
- }
+ LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(classload));
+ LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(classunload));
} else if (!strcmp(tail, ":gc")) {
LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(gc));
} else if (!strcmp(tail, ":jni")) {
@@ -3090,6 +3089,10 @@
// -Xnoagent
} else if (match_option(option, "-Xnoagent")) {
// For compatibility with classic. HotSpot refuses to load the old style agent.dll.
+ } else if (match_option(option, "-Xloggc:", &tail)) {
+ // Deprecated flag to redirect GC output to a file. -Xloggc:<filename>
+ log_warning(gc)("-Xloggc is deprecated. Will use -Xlog:gc:%s instead.", tail);
+ _gc_log_filename = os::strdup_check_oom(tail);
} else if (match_option(option, "-Xlog", &tail)) {
bool ret = false;
if (strcmp(tail, ":help") == 0) {
@@ -3999,6 +4002,24 @@
}
}
+bool Arguments::handle_deprecated_print_gc_flags() {
+ if (PrintGC) {
+ log_warning(gc)("-XX:+PrintGC is deprecated. Will use -Xlog:gc instead.");
+ }
+ if (PrintGCDetails) {
+ log_warning(gc)("-XX:+PrintGCDetails is deprecated. Will use -Xlog:gc* instead.");
+ }
+
+ if (_gc_log_filename != NULL) {
+ // -Xloggc was used to specify a filename
+ const char* gc_conf = PrintGCDetails ? "gc*" : "gc";
+ return LogConfiguration::parse_log_arguments(_gc_log_filename, gc_conf, NULL, NULL, NULL);
+ } else if (PrintGC || PrintGCDetails) {
+ LogConfiguration::configure_stdout(LogLevel::Info, !PrintGCDetails, LOG_TAGS(gc));
+ }
+ return true;
+}
+
// Parse entry point called from JNI_CreateJavaVM
jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) {
@@ -4147,6 +4168,10 @@
ScavengeRootsInCode = 1;
}
+ if (!handle_deprecated_print_gc_flags()) {
+ return JNI_EINVAL;
+ }
+
// Set object alignment values.
set_object_alignment();
--- a/hotspot/src/share/vm/runtime/arguments.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/arguments.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -294,6 +294,7 @@
// Option flags
static bool _has_profile;
+ static const char* _gc_log_filename;
// Value of the conservative maximum heap alignment needed
static size_t _conservative_max_heap_alignment;
@@ -400,6 +401,8 @@
static jint match_special_option_and_act(const JavaVMInitArgs* args,
ScopedVMInitArgs* args_out);
+ static bool handle_deprecated_print_gc_flags();
+
static jint parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args,
const JavaVMInitArgs *java_options_args,
const JavaVMInitArgs *cmd_line_args);
--- a/hotspot/src/share/vm/runtime/globals.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -2388,6 +2388,14 @@
"will sleep while yielding before giving up and resuming GC") \
range(0, max_juint) \
\
+ product(bool, PrintGC, false, \
+ "Print message at garbage collection. " \
+ "Deprecated, use -Xlog:gc instead.") \
+ \
+ product(bool, PrintGCDetails, false, \
+ "Print more details at garbage collection. " \
+ "Deprecated, use -Xlog:gc* instead.") \
+ \
develop(intx, ConcGCYieldTimeout, 0, \
"If non-zero, assert that GC threads yield within this " \
"number of milliseconds") \
@@ -2405,21 +2413,12 @@
product(bool, TraceClassPaths, false, \
"Trace processing of class paths") \
\
- product_rw(bool, TraceClassLoading, false, \
- "Trace all classes loaded") \
- \
product(bool, TraceClassLoadingPreorder, false, \
"Trace all classes loaded in order referenced (not loaded)") \
\
- product_rw(bool, TraceClassUnloading, false, \
- "Trace unloading of classes") \
- \
product_rw(bool, TraceLoaderConstraints, false, \
"Trace loader constraints") \
\
- develop(bool, TraceClassLoaderData, false, \
- "Trace class loader loader_data lifetime") \
- \
product(size_t, InitialBootClassLoaderMetaspaceSize, \
NOT_LP64(2200*K) LP64_ONLY(4*M), \
"Initial size of the boot class loader data metaspace") \
@@ -3249,7 +3248,7 @@
\
product(size_t, MinTLABSize, 2*K, \
"Minimum allowed TLAB size (in bytes)") \
- range(1, max_uintx) \
+ range(1, max_uintx/2) \
constraint(MinTLABSizeConstraintFunc,AfterMemoryInit) \
\
product(size_t, TLABSize, 0, \
@@ -3392,10 +3391,10 @@
"also has a smaller default value; see arguments.cpp.") \
range(0, 100) \
\
- product(uintx, MarkSweepAlwaysCompactCount, 4, \
+ product(uint, MarkSweepAlwaysCompactCount, 4, \
"How often should we fully compact the heap (ignoring the dead " \
"space parameters)") \
- range(1, max_uintx) \
+ range(1, max_juint) \
\
develop(uintx, GCExpandToAllocateDelayMillis, 0, \
"Delay between expansion and allocation (in milliseconds)") \
@@ -3948,7 +3947,7 @@
product(bool, PerfDisableSharedMem, false, \
"Store performance data in standard memory") \
\
- product(intx, PerfDataMemorySize, 64*K, \
+ product(intx, PerfDataMemorySize, 32*K, \
"Size of performance data memory region. Will be rounded " \
"up to a multiple of the native os page size.") \
range(128, 32*64*K) \
--- a/hotspot/src/share/vm/runtime/java.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/java.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -421,7 +421,10 @@
assert(_before_exit_status == BEFORE_EXIT_DONE, "invalid state");
return;
case BEFORE_EXIT_DONE:
- return;
+ // need block to avoid SS compiler bug
+ {
+ return;
+ }
}
}
--- a/hotspot/src/share/vm/runtime/os.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/os.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -273,7 +273,7 @@
default: {
// Dispatch the signal to java
HandleMark hm(THREAD);
- Klass* k = SystemDictionary::resolve_or_null(vmSymbols::sun_misc_Signal(), THREAD);
+ Klass* k = SystemDictionary::resolve_or_null(vmSymbols::jdk_internal_misc_Signal(), THREAD);
KlassHandle klass (THREAD, k);
if (klass.not_null()) {
JavaValue result(T_VOID);
@@ -1490,7 +1490,7 @@
if (logical_processors > 1) {
const unsigned int physical_packages =
os::active_processor_count() / logical_processors;
- if (physical_packages > server_processors) {
+ if (physical_packages >= server_processors) {
result = true;
}
} else {
--- a/hotspot/src/share/vm/runtime/reflection.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/reflection.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -939,10 +939,7 @@
int index = reflected_method->vtable_index();
method = reflected_method;
if (index != Method::nonvirtual_vtable_index) {
- // target_klass might be an arrayKlassOop but all vtables start at
- // the same place. The cast is to avoid virtual call and assertion.
- InstanceKlass* inst = (InstanceKlass*)target_klass();
- method = methodHandle(THREAD, inst->method_at_vtable(index));
+ method = methodHandle(THREAD, target_klass->method_at_vtable(index));
}
if (!method.is_null()) {
// Check for abstract methods as well
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -42,6 +42,8 @@
#include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/vframe.hpp"
+#include "trace/traceMacros.hpp"
+#include "trace/tracing.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#include "utilities/preserveException.hpp"
@@ -130,6 +132,10 @@
static volatile int gMonitorFreeCount = 0; // # on gFreeList
static volatile int gMonitorPopulation = 0; // # Extant -- in circulation
+static void post_monitor_inflate_event(EventJavaMonitorInflate&,
+ const oop,
+ const ObjectSynchronizer::InflateCause);
+
#define CHAINMARKER (cast_to_oop<intptr_t>(-1))
@@ -304,7 +310,9 @@
}
}
- ObjectSynchronizer::inflate(THREAD, object)->exit(true, THREAD);
+ ObjectSynchronizer::inflate(THREAD,
+ object,
+ inflate_cause_vm_internal)->exit(true, THREAD);
}
// -----------------------------------------------------------------------------
@@ -338,7 +346,9 @@
// must be non-zero to avoid looking like a re-entrant lock,
// and must not look locked either.
lock->set_displaced_header(markOopDesc::unused_mark());
- ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
+ ObjectSynchronizer::inflate(THREAD,
+ obj(),
+ inflate_cause_monitor_enter)->enter(THREAD);
}
// This routine is used to handle interpreter/compiler slow case
@@ -368,7 +378,9 @@
assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
}
- ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
+ ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD,
+ obj(),
+ inflate_cause_vm_internal);
return monitor->complete_exit(THREAD);
}
@@ -381,7 +393,9 @@
assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
}
- ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
+ ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD,
+ obj(),
+ inflate_cause_vm_internal);
monitor->reenter(recursion, THREAD);
}
@@ -396,7 +410,7 @@
assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
}
THREAD->set_current_pending_monitor_is_from_java(false);
- ObjectSynchronizer::inflate(THREAD, obj())->enter(THREAD);
+ ObjectSynchronizer::inflate(THREAD, obj(), inflate_cause_jni_enter)->enter(THREAD);
THREAD->set_current_pending_monitor_is_from_java(true);
}
@@ -410,7 +424,9 @@
}
assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
- ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj);
+ ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD,
+ obj,
+ inflate_cause_jni_exit);
// If this thread has locked the object, exit the monitor. Note: can't use
// monitor->check(CHECK); must exit even if an exception is pending.
if (monitor->check(THREAD)) {
@@ -453,7 +469,10 @@
TEVENT(wait - throw IAX);
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
}
- ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD, obj());
+ ObjectMonitor* monitor = ObjectSynchronizer::inflate(THREAD,
+ obj(),
+ inflate_cause_wait);
+
DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
monitor->wait(millis, true, THREAD);
@@ -473,7 +492,9 @@
TEVENT(wait - throw IAX);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
}
- ObjectSynchronizer::inflate(THREAD, obj()) -> wait(millis, false, THREAD);
+ ObjectSynchronizer::inflate(THREAD,
+ obj(),
+ inflate_cause_wait)->wait(millis, false, THREAD);
}
void ObjectSynchronizer::notify(Handle obj, TRAPS) {
@@ -486,7 +507,9 @@
if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
return;
}
- ObjectSynchronizer::inflate(THREAD, obj())->notify(THREAD);
+ ObjectSynchronizer::inflate(THREAD,
+ obj(),
+ inflate_cause_notify)->notify(THREAD);
}
// NOTE: see comment of notify()
@@ -500,7 +523,9 @@
if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
return;
}
- ObjectSynchronizer::inflate(THREAD, obj())->notifyAll(THREAD);
+ ObjectSynchronizer::inflate(THREAD,
+ obj(),
+ inflate_cause_notify)->notifyAll(THREAD);
}
// -----------------------------------------------------------------------------
@@ -749,7 +774,7 @@
}
// Inflate the monitor to set hash code
- monitor = ObjectSynchronizer::inflate(Self, obj);
+ monitor = ObjectSynchronizer::inflate(Self, obj, inflate_cause_hash_code);
// Load displaced header and check it has hash code
mark = monitor->header();
assert(mark->is_neutral(), "invariant");
@@ -1283,17 +1308,22 @@
assert(mark->monitor()->header()->is_neutral(), "monitor must record a good object header");
return mark->monitor();
}
- return ObjectSynchronizer::inflate(Thread::current(), obj);
+ return ObjectSynchronizer::inflate(Thread::current(),
+ obj,
+ inflate_cause_vm_internal);
}
+ObjectMonitor * NOINLINE ObjectSynchronizer::inflate(Thread * Self,
+ oop object,
+ const InflateCause cause) {
-ObjectMonitor * NOINLINE ObjectSynchronizer::inflate(Thread * Self,
- oop object) {
// Inflate mutates the heap ...
// Relaxing assertion for bug 6320749.
assert(Universe::verify_in_progress() ||
!SafepointSynchronize::is_at_safepoint(), "invariant");
+ EventJavaMonitorInflate event;
+
for (;;) {
const markOop mark = object->mark();
assert(!mark->has_bias_pattern(), "invariant");
@@ -1311,6 +1341,7 @@
assert(inf->header()->is_neutral(), "invariant");
assert(inf->object() == object, "invariant");
assert(ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is invalid");
+ event.cancel(); // let's not post an inflation event, unless we did the deed ourselves
return inf;
}
@@ -1423,6 +1454,9 @@
object->klass()->external_name());
}
}
+ if (event.should_commit()) {
+ post_monitor_inflate_event(event, object, cause);
+ }
return m;
}
@@ -1471,6 +1505,9 @@
object->klass()->external_name());
}
}
+ if (event.should_commit()) {
+ post_monitor_inflate_event(event, object, cause);
+ }
return m;
}
}
@@ -1742,6 +1779,33 @@
THREAD->clear_pending_exception();
}
+const char* ObjectSynchronizer::inflate_cause_name(const InflateCause cause) {
+ switch (cause) {
+ case inflate_cause_vm_internal: return "VM Internal";
+ case inflate_cause_monitor_enter: return "Monitor Enter";
+ case inflate_cause_wait: return "Monitor Wait";
+ case inflate_cause_notify: return "Monitor Notify";
+ case inflate_cause_hash_code: return "Monitor Hash Code";
+ case inflate_cause_jni_enter: return "JNI Monitor Enter";
+ case inflate_cause_jni_exit: return "JNI Monitor Exit";
+ default:
+ ShouldNotReachHere();
+ }
+ return "Unknown";
+}
+
+static void post_monitor_inflate_event(EventJavaMonitorInflate& event,
+ const oop obj,
+ const ObjectSynchronizer::InflateCause cause) {
+#if INCLUDE_TRACE
+ assert(event.should_commit(), "check outside");
+ event.set_klass(obj->klass());
+ event.set_address((TYPE_ADDRESS)(uintptr_t)(void*)obj);
+ event.set_cause((u1)cause);
+ event.commit();
+#endif
+}
+
//------------------------------------------------------------------------------
// Debugging code
--- a/hotspot/src/share/vm/runtime/synchronizer.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/synchronizer.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -42,6 +42,18 @@
owner_none,
owner_other
} LockOwnership;
+
+ typedef enum {
+ inflate_cause_vm_internal = 0,
+ inflate_cause_monitor_enter = 1,
+ inflate_cause_wait = 2,
+ inflate_cause_notify = 3,
+ inflate_cause_hash_code = 4,
+ inflate_cause_jni_enter = 5,
+ inflate_cause_jni_exit = 6,
+ inflate_cause_nof = 7 // Number of causes
+ } InflateCause;
+
// exit must be implemented non-blocking, since the compiler cannot easily handle
// deoptimization at monitor exit. Hence, it does not take a Handle argument.
@@ -94,9 +106,10 @@
static void omFlush(Thread * Self);
// Inflate light weight monitor to heavy weight monitor
- static ObjectMonitor* inflate(Thread * Self, oop obj);
+ static ObjectMonitor* inflate(Thread * Self, oop obj, const InflateCause cause);
// This version is only for internal use
static ObjectMonitor* inflate_helper(oop obj);
+ static const char* inflate_cause_name(const InflateCause cause);
// Returns the identity hash value for an oop
// NOTE: It may cause monitor inflation
--- a/hotspot/src/share/vm/runtime/thread.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -31,6 +31,7 @@
#include "code/codeCacheExtensions.hpp"
#include "code/scopeDesc.hpp"
#include "compiler/compileBroker.hpp"
+#include "compiler/compileTask.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/gcLocker.inline.hpp"
#include "gc/shared/workgroup.hpp"
@@ -2884,6 +2885,20 @@
print_thread_state_on(st);
_safepoint_state->print_on(st);
#endif // PRODUCT
+ if (is_Compiler_thread()) {
+ CompilerThread* ct = (CompilerThread*)this;
+ if (ct->task() != NULL) {
+ st->print(" Compiling: ");
+ ct->task()->print(st, NULL, true, false);
+ } else {
+ st->print(" No compile task");
+ }
+ st->cr();
+ }
+}
+
+void JavaThread::print_name_on_error(outputStream* st, char *buf, int buflen) const {
+ st->print("%s", get_thread_name_string(buf, buflen));
}
// Called by fatal error handler. The difference between this and
@@ -4386,7 +4401,6 @@
wt->print_on(st);
st->cr();
}
- CompileBroker::print_compiler_threads_on(st);
st->flush();
}
@@ -4439,8 +4453,24 @@
current->print_on_error(st, buf, buflen);
st->cr();
}
+ st->cr();
+ st->print_cr("Threads with active compile tasks:");
+ print_threads_compiling(st, buf, buflen);
}
+void Threads::print_threads_compiling(outputStream* st, char* buf, int buflen) {
+ ALL_JAVA_THREADS(thread) {
+ if (thread->is_Compiler_thread()) {
+ CompilerThread* ct = (CompilerThread*) thread;
+ if (ct->task() != NULL) {
+ thread->print_name_on_error(st, buf, buflen);
+ ct->task()->print(st, NULL, true, true);
+ }
+ }
+ }
+}
+
+
// Internal SpinLock and Mutex
// Based on ParkEvent
--- a/hotspot/src/share/vm/runtime/thread.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/thread.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1660,6 +1660,7 @@
void print_thread_state_on(outputStream*) const PRODUCT_RETURN;
void print_thread_state() const PRODUCT_RETURN;
void print_on_error(outputStream* st, char* buf, int buflen) const;
+ void print_name_on_error(outputStream* st, char* buf, int buflen) const;
void verify();
const char* get_thread_name() const;
private:
@@ -2158,6 +2159,7 @@
print_on(tty, print_stacks, internal_format, false /* no concurrent lock printed */);
}
static void print_on_error(outputStream* st, Thread* current, char* buf, int buflen);
+ static void print_threads_compiling(outputStream* st, char* buf, int buflen);
// Get Java threads that are waiting to enter a monitor. If doLock
// is true, then Threads_lock is grabbed as needed. Otherwise, the
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -298,7 +298,6 @@
nonstatic_field(ArrayKlass, _dimension, int) \
volatile_nonstatic_field(ArrayKlass, _higher_dimension, Klass*) \
volatile_nonstatic_field(ArrayKlass, _lower_dimension, Klass*) \
- nonstatic_field(ArrayKlass, _vtable_len, int) \
nonstatic_field(CompiledICHolder, _holder_method, Method*) \
nonstatic_field(CompiledICHolder, _holder_klass, Klass*) \
nonstatic_field(ConstantPool, _tags, Array<u1>*) \
@@ -332,7 +331,6 @@
nonstatic_field(InstanceKlass, _major_version, u2) \
nonstatic_field(InstanceKlass, _init_state, u1) \
nonstatic_field(InstanceKlass, _init_thread, Thread*) \
- nonstatic_field(InstanceKlass, _vtable_len, int) \
nonstatic_field(InstanceKlass, _itable_len, int) \
nonstatic_field(InstanceKlass, _reference_type, u1) \
volatile_nonstatic_field(InstanceKlass, _oop_map_cache, OopMapCache*) \
@@ -358,6 +356,7 @@
nonstatic_field(Klass, _access_flags, AccessFlags) \
nonstatic_field(Klass, _prototype_header, markOop) \
nonstatic_field(Klass, _next_sibling, Klass*) \
+ nonstatic_field(Klass, _vtable_len, int) \
nonstatic_field(vtableEntry, _method, Method*) \
nonstatic_field(MethodData, _size, int) \
nonstatic_field(MethodData, _method, Method*) \
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -485,18 +485,6 @@
}
}
-void VM_PrintCompileQueue::doit() {
- CompileBroker::print_compile_queues(_out);
-}
-
-void VM_PrintCodeList::doit() {
- CodeCache::print_codelist(_out);
-}
-
-void VM_PrintCodeCache::doit() {
- CodeCache::print_layout(_out);
-}
-
#if INCLUDE_SERVICES
void VM_PrintClassHierarchy::doit() {
KlassHierarchy::print_class_hierarchy(_out, _print_interfaces, _print_subclasses, _classname);
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -105,9 +105,6 @@
template(DumpHashtable) \
template(DumpTouchedMethods) \
template(MarkActiveNMethods) \
- template(PrintCompileQueue) \
- template(PrintCodeList) \
- template(PrintCodeCache) \
template(PrintClassHierarchy) \
class VM_Operation: public CHeapObj<mtInternal> {
@@ -424,37 +421,6 @@
void doit();
};
-class VM_PrintCompileQueue: public VM_Operation {
- private:
- outputStream* _out;
-
- public:
- VM_PrintCompileQueue(outputStream* st) : _out(st) {}
- VMOp_Type type() const { return VMOp_PrintCompileQueue; }
- Mode evaluation_mode() const { return _no_safepoint; }
- void doit();
-};
-
-class VM_PrintCodeList: public VM_Operation {
- private:
- outputStream* _out;
-
- public:
- VM_PrintCodeList(outputStream* st) : _out(st) {}
- VMOp_Type type() const { return VMOp_PrintCodeList; }
- void doit();
-};
-
-class VM_PrintCodeCache: public VM_Operation {
- private:
- outputStream* _out;
-
- public:
- VM_PrintCodeCache(outputStream* st) : _out(st) {}
- VMOp_Type type() const { return VMOp_PrintCodeCache; }
- void doit();
-};
-
#if INCLUDE_SERVICES
class VM_PrintClassHierarchy: public VM_Operation {
private:
--- a/hotspot/src/share/vm/services/classLoadingService.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/services/classLoadingService.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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
@@ -33,6 +33,8 @@
#include "utilities/dtrace.hpp"
#include "utilities/macros.hpp"
#include "utilities/defaultStream.hpp"
+#include "logging/log.hpp"
+#include "logging/logConfiguration.hpp"
#ifdef DTRACE_ENABLED
@@ -135,9 +137,9 @@
}
}
- if (TraceClassUnloading) {
+ if (log_is_enabled(Info, classunload)) {
ResourceMark rm;
- tty->print_cr("[Unloading class %s " INTPTR_FORMAT "]", k->external_name(), p2i(k));
+ log_info(classunload)("unloading class %s " INTPTR_FORMAT , k->external_name(), p2i(k));
}
}
@@ -179,12 +181,13 @@
bool ClassLoadingService::set_verbose(bool verbose) {
MutexLocker m(Management_lock);
-
// verbose will be set to the previous value
- Flag::Error error = CommandLineFlags::boolAtPut("TraceClassLoading", &verbose, Flag::MANAGEMENT);
- assert(error==Flag::SUCCESS, "Setting TraceClassLoading flag failed with error %s", Flag::flag_error_str(error));
+ if (verbose) {
+ LogConfiguration::parse_log_arguments("stdout", "classload=info", NULL, NULL, NULL);
+ } else {
+ LogConfiguration::parse_log_arguments("stdout", "classload=off", NULL, NULL, NULL);
+ }
reset_trace_class_unloading();
-
return verbose;
}
@@ -192,8 +195,11 @@
void ClassLoadingService::reset_trace_class_unloading() {
assert(Management_lock->owned_by_self(), "Must own the Management_lock");
bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose();
- Flag::Error error = CommandLineFlags::boolAtPut("TraceClassUnloading", &value, Flag::MANAGEMENT);
- assert(error==Flag::SUCCESS, "Setting TraceClassUnLoading flag failed with error %s", Flag::flag_error_str(error));
+ if (value) {
+ LogConfiguration::parse_log_arguments("stdout", "classunload=info", NULL, NULL, NULL);
+ } else {
+ LogConfiguration::parse_log_arguments("stdout", "classunload=off", NULL, NULL, NULL);
+ }
}
GrowableArray<KlassHandle>* LoadedClassesEnumerator::_loaded_classes = NULL;
--- a/hotspot/src/share/vm/services/classLoadingService.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/services/classLoadingService.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, 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,6 +25,7 @@
#ifndef SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
#define SHARE_VM_SERVICES_CLASSLOADINGSERVICE_HPP
+#include "logging/log.hpp"
#include "runtime/handles.hpp"
#include "runtime/perfData.hpp"
#include "utilities/growableArray.hpp"
@@ -54,7 +55,7 @@
public:
static void init();
- static bool get_verbose() { return TraceClassLoading; }
+ static bool get_verbose() { return log_is_enabled(Info, classload); }
static bool set_verbose(bool verbose);
static void reset_trace_class_unloading() NOT_MANAGEMENT_RETURN;
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -832,18 +832,15 @@
}
void CompileQueueDCmd::execute(DCmdSource source, TRAPS) {
- VM_PrintCompileQueue printCompileQueueOp(output());
- VMThread::execute(&printCompileQueueOp);
+ CompileBroker::print_compile_queues(output());
}
void CodeListDCmd::execute(DCmdSource source, TRAPS) {
- VM_PrintCodeList printCodeListOp(output());
- VMThread::execute(&printCodeListOp);
+ CodeCache::print_codelist(output());
}
void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
- VM_PrintCodeCache printCodeCacheOp(output());
- VMThread::execute(&printCodeCacheOp);
+ CodeCache::print_layout(output());
}
void CompilerDirectivesPrintDCmd::execute(DCmdSource source, TRAPS) {
--- a/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright 2008, 2009, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -1143,8 +1143,8 @@
builder()->CreateArrayAddress(
klass,
SharkType::Method_type(),
- vtableEntry::size() * wordSize,
- in_ByteSize(InstanceKlass::vtable_start_offset() * wordSize),
+ vtableEntry::size_in_bytes(),
+ Klass::vtable_start_offset(),
LLVMValue::intptr_constant(vtable_index)),
"callee");
}
@@ -1166,12 +1166,12 @@
Value *vtable_start = builder()->CreateAdd(
builder()->CreatePtrToInt(object_klass, SharkType::intptr_type()),
LLVMValue::intptr_constant(
- InstanceKlass::vtable_start_offset() * HeapWordSize),
+ in_bytes(Klass::vtable_start_offset())),
"vtable_start");
Value *vtable_length = builder()->CreateValueOfStructEntry(
object_klass,
- in_ByteSize(InstanceKlass::vtable_length_offset() * HeapWordSize),
+ Klass::vtable_length_offset(),
SharkType::jint_type(),
"vtable_length");
vtable_length =
@@ -1182,7 +1182,7 @@
vtable_start,
builder()->CreateShl(
vtable_length,
- LLVMValue::intptr_constant(exact_log2(vtableEntry::size() * wordSize))),
+ LLVMValue::intptr_constant(exact_log2(vtableEntry::size_in_bytes()))),
needs_aligning ? "" : "itable_start");
if (needs_aligning) {
itable_start = builder()->CreateAnd(
--- a/hotspot/src/share/vm/trace/trace.xml Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/trace/trace.xml Wed Jul 05 21:21:58 2017 +0200
@@ -109,6 +109,13 @@
<value type="ADDRESS" field="address" label="Monitor Address" description="Address of object waited on" relation="JAVA_MONITOR_ADDRESS"/>
</event>
+ <event id="JavaMonitorInflate" path="java/monitor_inflate" label="Java Monitor Inflated"
+ has_thread="true" has_stacktrace="true" is_instant="false">
+ <value type="CLASS" field="klass" label="Monitor Class"/>
+ <value type="ADDRESS" field="address" label="Monitor Address" relation="JAVA_MONITOR_ADDRESS"/>
+ <value type="INFLATECAUSE" field="cause" label="Cause" description="Cause of inflation"/>
+ </event>
+
<event id="ReservedStackActivation" path="java/reserved_stack_activation" label="Reserved Stack Activation" description="Activation of Reserved Stack Area caused by stack overflow with ReservedStackAccess annotated method in call stack"
has_thread="true" has_stacktrace="true" is_instant="true">
<value type="METHOD" field="method" label="Java Method"/>
--- a/hotspot/src/share/vm/trace/traceEventClasses.xsl Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/trace/traceEventClasses.xsl Wed Jul 05 21:21:58 2017 +0200
@@ -56,7 +56,8 @@
void set_endtime(const Ticks& time) {}
bool should_commit() const { return false; }
static bool is_enabled() { return false; }
- void commit() const {}
+ void commit() {}
+ void cancel() {}
};
<xsl:apply-templates select="trace/events/struct" mode="empty"/>
--- a/hotspot/src/share/vm/trace/tracetypes.xml Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/trace/tracetypes.xml Wed Jul 05 21:21:58 2017 +0200
@@ -170,12 +170,16 @@
type="U1" jvm_type="FLAGVALUEORIGIN">
<value type="UTF8" field="origin" label="origin" />
</content_type>
-
+
<content_type id="CodeBlobType" hr_name="Code Blob Type"
type="U1" jvm_type="CODEBLOBTYPE">
<value type="UTF8" field="type" label="type" />
</content_type>
+ <content_type id="InflateCause" hr_name="Inflation Cause"
+ type="U1" jvm_type="INFLATECAUSE">
+ <value type="UTF8" field="cause" label="cause" />
+ </content_type>
</content_types>
@@ -381,5 +385,8 @@
<primary_type symbol="CODEBLOBTYPE" datatype="U1"
contenttype="CODEBLOBTYPE" type="u1" sizeop="sizeof(u1)" />
+ <!-- INFLATECAUSE -->
+ <primary_type symbol="INFLATECAUSE" datatype="U1"
+ contenttype="INFLATECAUSE" type="u1" sizeop="sizeof(u1)" />
</primary_types>
</types>
--- a/hotspot/src/share/vm/utilities/debug.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/utilities/debug.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -461,7 +461,7 @@
extern "C" void dump_vtable(address p) {
Command c("dump_vtable");
Klass* k = (Klass*)p;
- InstanceKlass::cast(k)->vtable()->print();
+ k->vtable()->print();
}
--- a/hotspot/src/share/vm/utilities/globalDefinitions.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -85,6 +85,8 @@
assert( 1 == sizeof( u1), "wrong size for basic type");
assert( 2 == sizeof( u2), "wrong size for basic type");
assert( 4 == sizeof( u4), "wrong size for basic type");
+ assert(wordSize == BytesPerWord, "should be the same since they're used interchangeably");
+ assert(wordSize == HeapWordSize, "should be the same since they're also used interchangeably");
int num_type_chars = 0;
for (int i = 0; i < 99; i++) {
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -157,7 +157,6 @@
// Analogous opaque struct for metadata allocated from
// metaspaces.
class MetaWord {
- friend class VMStructs;
private:
char* i;
};
@@ -486,7 +485,7 @@
#define is_size_aligned_(size, alignment) ((size) == (align_size_up_(size, alignment)))
-inline void* align_ptr_up(void* ptr, size_t alignment) {
+inline void* align_ptr_up(const void* ptr, size_t alignment) {
return (void*)align_size_up((intptr_t)ptr, (intptr_t)alignment);
}
@@ -494,10 +493,15 @@
return (void*)align_size_down((intptr_t)ptr, (intptr_t)alignment);
}
-// Align objects by rounding up their size, in HeapWord units.
+// Align metaspace objects by rounding up to natural word boundary
-#define align_object_size_(size) align_size_up_(size, MinObjAlignment)
+inline intptr_t align_metadata_size(intptr_t size) {
+ return align_size_up(size, 1);
+}
+// Align objects in the Java Heap by rounding up their size, in HeapWord units.
+// Since the size is given in words this is somewhat of a nop, but
+// distinguishes it from align_object_size.
inline intptr_t align_object_size(intptr_t size) {
return align_size_up(size, MinObjAlignment);
}
@@ -512,10 +516,6 @@
return align_size_up(offset, HeapWordsPerLong);
}
-inline void* align_pointer_up(const void* addr, size_t size) {
- return (void*) align_size_up_((uintptr_t)addr, size);
-}
-
// Align down with a lower bound. If the aligning results in 0, return 'alignment'.
inline size_t align_size_down_bounded(size_t size, size_t alignment) {
--- a/hotspot/src/share/vm/utilities/growableArray.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/utilities/growableArray.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -169,7 +169,9 @@
: GenericGrowableArray(initial_size, 0, C_heap, F) {
_data = (E*)raw_allocate(sizeof(E));
// Needed for Visual Studio 2012 and older
+#ifdef _MSC_VER
#pragma warning(suppress: 4345)
+#endif
for (int i = 0; i < _max; i++) ::new ((void*)&_data[i]) E();
}
@@ -422,7 +424,9 @@
int i = 0;
for ( ; i < _len; i++) ::new ((void*)&newData[i]) E(_data[i]);
// Needed for Visual Studio 2012 and older
+#ifdef _MSC_VER
#pragma warning(suppress: 4345)
+#endif
for ( ; i < _max; i++) ::new ((void*)&newData[i]) E();
for (i = 0; i < old_max; i++) _data[i].~E();
if (on_C_heap() && _data != NULL) {
--- a/hotspot/src/share/vm/utilities/internalVMTests.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/utilities/internalVMTests.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -30,103 +30,62 @@
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
-#define run_unit_test(unit_test_function_call) \
- tty->print_cr("Running test: " #unit_test_function_call); \
- unit_test_function_call
+#define run_unit_test(unit_test_function_call) \
+ void unit_test_function_call(); \
+ run_test(#unit_test_function_call, unit_test_function_call);
-// Forward declaration
-void TestDependencyContext_test();
-void test_semaphore();
-void TestOS_test();
-void TestReservedSpace_test();
-void TestReserveMemorySpecial_test();
-void TestVirtualSpace_test();
-void TestMetaspaceAux_test();
-void TestMetachunk_test();
-void TestVirtualSpaceNode_test();
-void TestNewSize_test();
-void TestOldSize_test();
-void TestKlass_test();
-void TestBitMap_test();
-void TestAsUtf8();
-void Test_linked_list();
-void TestResourcehash_test();
-void TestChunkedList_test();
-void Test_log_length();
-void Test_TempNewSymbol();
-void GlobalDefinitions_test();
-void GCTimer_test();
-void arrayOopDesc_test();
-void CollectedHeap_test();
-void QuickSort_test();
-void GuardedMemory_test();
-void AltHashing_test();
-void ObjectMonitor_test();
-void JSON_test();
-void DirectivesParser_test();
-
-#if INCLUDE_VM_STRUCTS
-void VMStructs_test();
-#endif
-
-#if INCLUDE_ALL_GCS
-void TestOldFreeSpaceCalculation_test();
-void TestG1BiasedArray_test();
-void TestBufferingOopClosure_test();
-void TestCodeCacheRemSet_test();
-void FreeRegionList_test();
-void IHOP_test();
-void test_memset_with_concurrent_readers();
-void TestPredictions_test();
-void WorkerDataArray_test();
-#endif
+void InternalVMTests::run_test(const char* name, void (*test)()) {
+ tty->print_cr("Running test: %s", name);
+ test();
+}
void InternalVMTests::run() {
tty->print_cr("Running internal VM tests");
- run_unit_test(TestDependencyContext_test());
- run_unit_test(test_semaphore());
- run_unit_test(TestOS_test());
- run_unit_test(TestReservedSpace_test());
- run_unit_test(TestReserveMemorySpecial_test());
- run_unit_test(TestVirtualSpace_test());
- run_unit_test(TestMetaspaceAux_test());
- run_unit_test(TestMetachunk_test());
- run_unit_test(TestVirtualSpaceNode_test());
- run_unit_test(GlobalDefinitions_test());
- run_unit_test(GCTimer_test());
- run_unit_test(arrayOopDesc_test());
- run_unit_test(CollectedHeap_test());
- run_unit_test(QuickSort_test());
- run_unit_test(GuardedMemory_test());
- run_unit_test(AltHashing_test());
- run_unit_test(TestNewSize_test());
- run_unit_test(TestOldSize_test());
- run_unit_test(TestKlass_test());
- run_unit_test(TestBitMap_test());
- run_unit_test(TestAsUtf8());
- run_unit_test(TestResourcehash_test());
- run_unit_test(ObjectMonitor_test());
- run_unit_test(Test_linked_list());
- run_unit_test(TestChunkedList_test());
- run_unit_test(JSON_test());
- run_unit_test(Test_log_length());
- run_unit_test(DirectivesParser_test());
- run_unit_test(Test_TempNewSymbol());
+ run_unit_test(TestDependencyContext_test);
+ run_unit_test(test_semaphore);
+ run_unit_test(TestOS_test);
+ run_unit_test(TestReservedSpace_test);
+ run_unit_test(TestReserveMemorySpecial_test);
+ run_unit_test(TestVirtualSpace_test);
+ run_unit_test(TestMetaspaceAux_test);
+ run_unit_test(TestMetachunk_test);
+ run_unit_test(TestVirtualSpaceNode_test);
+ run_unit_test(GlobalDefinitions_test);
+ run_unit_test(GCTimer_test);
+ run_unit_test(arrayOopDesc_test);
+ run_unit_test(CollectedHeap_test);
+ run_unit_test(QuickSort_test);
+ run_unit_test(GuardedMemory_test);
+ run_unit_test(AltHashing_test);
+ run_unit_test(TestNewSize_test);
+ run_unit_test(TestOldSize_test);
+ run_unit_test(TestKlass_test);
+ run_unit_test(TestBitMap_test);
+ run_unit_test(TestAsUtf8);
+ run_unit_test(TestResourcehash_test);
+ run_unit_test(ObjectMonitor_test);
+ run_unit_test(Test_linked_list);
+ run_unit_test(TestChunkedList_test);
+ run_unit_test(JSON_test);
+ run_unit_test(Test_log_length);
+ run_unit_test(Test_configure_stdout);
+ run_unit_test(DirectivesParser_test);
+ run_unit_test(Test_TempNewSymbol);
#if INCLUDE_VM_STRUCTS
- run_unit_test(VMStructs_test());
+ run_unit_test(VMStructs_test);
#endif
#if INCLUDE_ALL_GCS
- run_unit_test(TestOldFreeSpaceCalculation_test());
- run_unit_test(TestG1BiasedArray_test());
- run_unit_test(TestBufferingOopClosure_test());
- run_unit_test(TestCodeCacheRemSet_test());
+ run_unit_test(TestOldFreeSpaceCalculation_test);
+ run_unit_test(TestG1BiasedArray_test);
+ run_unit_test(TestBufferingOopClosure_test);
+ run_unit_test(TestCodeCacheRemSet_test);
if (UseG1GC) {
- run_unit_test(FreeRegionList_test());
- run_unit_test(IHOP_test());
+ run_unit_test(FreeRegionList_test);
+ run_unit_test(IHOP_test);
}
- run_unit_test(test_memset_with_concurrent_readers());
- run_unit_test(TestPredictions_test());
- run_unit_test(WorkerDataArray_test());
+ run_unit_test(test_memset_with_concurrent_readers);
+ run_unit_test(TestPredictions_test);
+ run_unit_test(WorkerDataArray_test);
#endif
tty->print_cr("All internal VM tests passed");
}
--- a/hotspot/src/share/vm/utilities/internalVMTests.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/utilities/internalVMTests.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -30,6 +30,7 @@
#include "memory/allocation.hpp"
class InternalVMTests : public AllStatic {
+ static void run_test(const char* name, void (*test)());
public:
static void run();
};
--- a/hotspot/src/share/vm/utilities/ostream.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/utilities/ostream.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -44,6 +44,8 @@
_newlines = 0;
_precount = 0;
_indentation = 0;
+ _scratch = NULL;
+ _scratch_len = 0;
}
outputStream::outputStream(int width, bool has_time_stamps) {
@@ -52,6 +54,8 @@
_newlines = 0;
_precount = 0;
_indentation = 0;
+ _scratch = NULL;
+ _scratch_len = 0;
if (has_time_stamps) _stamp.update();
}
@@ -119,38 +123,47 @@
return result;
}
+void outputStream::do_vsnprintf_and_write_with_automatic_buffer(const char* format, va_list ap, bool add_cr) {
+ char buffer[O_BUFLEN];
+ size_t len;
+ const char* str = do_vsnprintf(buffer, sizeof(buffer), format, ap, add_cr, len);
+ write(str, len);
+}
+
+void outputStream::do_vsnprintf_and_write_with_scratch_buffer(const char* format, va_list ap, bool add_cr) {
+ size_t len;
+ const char* str = do_vsnprintf(_scratch, _scratch_len, format, ap, add_cr, len);
+ write(str, len);
+}
+
+void outputStream::do_vsnprintf_and_write(const char* format, va_list ap, bool add_cr) {
+ if (_scratch) {
+ do_vsnprintf_and_write_with_scratch_buffer(format, ap, add_cr);
+ } else {
+ do_vsnprintf_and_write_with_automatic_buffer(format, ap, add_cr);
+ }
+}
+
void outputStream::print(const char* format, ...) {
- char buffer[O_BUFLEN];
va_list ap;
va_start(ap, format);
- size_t len;
- const char* str = do_vsnprintf(buffer, O_BUFLEN, format, ap, false, len);
- write(str, len);
+ do_vsnprintf_and_write(format, ap, false);
va_end(ap);
}
void outputStream::print_cr(const char* format, ...) {
- char buffer[O_BUFLEN];
va_list ap;
va_start(ap, format);
- size_t len;
- const char* str = do_vsnprintf(buffer, O_BUFLEN, format, ap, true, len);
- write(str, len);
+ do_vsnprintf_and_write(format, ap, true);
va_end(ap);
}
void outputStream::vprint(const char *format, va_list argptr) {
- char buffer[O_BUFLEN];
- size_t len;
- const char* str = do_vsnprintf(buffer, O_BUFLEN, format, argptr, false, len);
- write(str, len);
+ do_vsnprintf_and_write(format, argptr, false);
}
void outputStream::vprint_cr(const char* format, va_list argptr) {
- char buffer[O_BUFLEN];
- size_t len;
- const char* str = do_vsnprintf(buffer, O_BUFLEN, format, argptr, true, len);
- write(str, len);
+ do_vsnprintf_and_write(format, argptr, true);
}
void outputStream::fill_to(int col) {
@@ -367,7 +380,7 @@
char* get_datetime_string(char *buf, size_t len) {
os::local_time_string(buf, len);
int i = (int)strlen(buf);
- while (i-- >= 0) {
+ while (--i >= 0) {
if (buf[i] == ' ') buf[i] = '_';
else if (buf[i] == ':') buf[i] = '-';
}
@@ -958,53 +971,6 @@
}
}
-staticBufferStream::staticBufferStream(char* buffer, size_t buflen,
- outputStream *outer_stream) {
- _buffer = buffer;
- _buflen = buflen;
- _outer_stream = outer_stream;
- // compile task prints time stamp relative to VM start
- _stamp.update_to(1);
-}
-
-void staticBufferStream::write(const char* c, size_t len) {
- _outer_stream->print_raw(c, (int)len);
-}
-
-void staticBufferStream::flush() {
- _outer_stream->flush();
-}
-
-void staticBufferStream::print(const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- size_t len;
- const char* str = do_vsnprintf(_buffer, _buflen, format, ap, false, len);
- write(str, len);
- va_end(ap);
-}
-
-void staticBufferStream::print_cr(const char* format, ...) {
- va_list ap;
- va_start(ap, format);
- size_t len;
- const char* str = do_vsnprintf(_buffer, _buflen, format, ap, true, len);
- write(str, len);
- va_end(ap);
-}
-
-void staticBufferStream::vprint(const char *format, va_list argptr) {
- size_t len;
- const char* str = do_vsnprintf(_buffer, _buflen, format, argptr, false, len);
- write(str, len);
-}
-
-void staticBufferStream::vprint_cr(const char* format, va_list argptr) {
- size_t len;
- const char* str = do_vsnprintf(_buffer, _buflen, format, argptr, true, len);
- write(str, len);
-}
-
bufferedStream::bufferedStream(size_t initial_size, size_t bufmax) : outputStream() {
buffer_length = initial_size;
buffer = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal);
@@ -1133,7 +1099,7 @@
void logStream::write(const char* s, size_t len) {
if (len > 0 && s[len - 1] == '\n') {
_current_line.write(s, len - 1);
- _log_func(_current_line.as_string());
+ _log_func("%s", _current_line.as_string());
_current_line.reset();
} else {
_current_line.write(s, len);
--- a/hotspot/src/share/vm/utilities/ostream.hpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/utilities/ostream.hpp Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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,6 +27,7 @@
#include "memory/allocation.hpp"
#include "runtime/timer.hpp"
+#include "utilities/globalDefinitions.hpp"
class GCId;
DEBUG_ONLY(class ResourceMark;)
@@ -49,6 +50,8 @@
int _newlines; // number of '\n' output so far
julong _precount; // number of chars output, less _position
TimeStamp _stamp; // for time stamps
+ char* _scratch; // internal scratch buffer for printf
+ size_t _scratch_len; // size of internal scratch buffer
void update_position(const char* s, size_t len);
static const char* do_vsnprintf(char* buffer, size_t buflen,
@@ -56,6 +59,13 @@
bool add_cr,
size_t& result_len) ATTRIBUTE_PRINTF(3, 0);
+ // calls do_vsnprintf and writes output to stream; uses an on-stack buffer.
+ void do_vsnprintf_and_write_with_automatic_buffer(const char* format, va_list ap, bool add_cr) ATTRIBUTE_PRINTF(2, 0);
+ // calls do_vsnprintf and writes output to stream; uses the user-provided buffer;
+ void do_vsnprintf_and_write_with_scratch_buffer(const char* format, va_list ap, bool add_cr) ATTRIBUTE_PRINTF(2, 0);
+ // calls do_vsnprintf, then writes output to stream.
+ void do_vsnprintf_and_write(const char* format, va_list ap, bool add_cr) ATTRIBUTE_PRINTF(2, 0);
+
public:
// creation
outputStream(int width = 80);
@@ -119,6 +129,10 @@
virtual void rotate_log(bool force, outputStream* out = NULL) {} // GC log rotation
virtual ~outputStream() {} // close properly on deletion
+ // Caller may specify their own scratch buffer to use for printing; otherwise,
+ // an automatic buffer on the stack (with O_BUFLEN len) is used.
+ void set_scratch_buffer(char* p, size_t len) { _scratch = p; _scratch_len = len; }
+
void dec_cr() { dec(); cr(); }
void inc_cr() { inc(); cr(); }
};
@@ -236,7 +250,7 @@
class logStream : public outputStream {
private:
stringStream _current_line;
- void (*_log_func)(const char* fmt, ...);
+ void (*_log_func)(const char* fmt, ...) ATTRIBUTE_PRINTF(1, 2);
public:
void write(const char* s, size_t len);
logStream(void (*log_func)(const char* fmt, ...)) : _log_func(log_func) {}
@@ -250,26 +264,6 @@
void ostream_exit();
void ostream_abort();
-// staticBufferStream uses a user-supplied buffer for all formatting.
-// Used for safe formatting during fatal error handling. Not MT safe.
-// Do not share the stream between multiple threads.
-class staticBufferStream : public outputStream {
- private:
- char* _buffer;
- size_t _buflen;
- outputStream* _outer_stream;
- public:
- staticBufferStream(char* buffer, size_t buflen,
- outputStream *outer_stream);
- ~staticBufferStream() {};
- virtual void write(const char* c, size_t len);
- void flush();
- void print(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
- void print_cr(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
- void vprint(const char *format, va_list argptr) ATTRIBUTE_PRINTF(2, 0);
- void vprint_cr(const char* format, va_list argptr) ATTRIBUTE_PRINTF(2, 0);
-};
-
// In the non-fixed buffer case an underlying buffer will be created and
// managed in C heap. Not MT-safe.
class bufferedStream : public outputStream {
--- a/hotspot/src/share/vm/utilities/vmError.cpp Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Wed Jul 05 21:21:58 2017 +0200
@@ -987,10 +987,12 @@
volatile intptr_t VMError::first_error_tid = -1;
// An error could happen before tty is initialized or after it has been
-// destroyed. Here we use a very simple unbuffered fdStream for printing.
-// Only out.print_raw() and out.print_raw_cr() should be used, as other
-// printing methods need to allocate large buffer on stack. To format a
-// string, use jio_snprintf() with a static buffer or use staticBufferStream.
+// destroyed.
+// Please note: to prevent large stack allocations, the log- and
+// output-stream use a global scratch buffer for format printing.
+// (see VmError::report_and_die(). Access to those streams is synchronized
+// in VmError::report_and_die() - there is only one reporting thread at
+// any given time.
fdStream VMError::out(defaultStream::output_fd());
fdStream VMError::log; // error log used by VMError::report_and_die()
@@ -1100,6 +1102,8 @@
{
// Don't allocate large buffer on stack
static char buffer[O_BUFLEN];
+ out.set_scratch_buffer(buffer, sizeof(buffer));
+ log.set_scratch_buffer(buffer, sizeof(buffer));
// How many errors occurred in error handler when reporting first_error.
static int recursive_error_count;
@@ -1186,8 +1190,7 @@
// print to screen
if (!out_done) {
- staticBufferStream sbs(buffer, sizeof(buffer), &out);
- report(&sbs, false);
+ report(&out, false);
out_done = true;
@@ -1215,8 +1218,7 @@
}
}
- staticBufferStream sbs(buffer, O_BUFLEN, &log);
- report(&sbs, true);
+ report(&log, true);
_current_step = 0;
_current_step_info = "";
--- a/hotspot/test/compiler/compilercontrol/commandfile/PrintTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/compilercontrol/commandfile/PrintTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -26,6 +26,7 @@
* @bug 8137167
* @summary Tests CompileCommand=print
* @library /testlibrary /test/lib /compiler/testlibrary ../share /
+ * @ignore 8140354
* @build compiler.compilercontrol.commandfile.PrintTest
* pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
* compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.*
--- a/hotspot/test/compiler/compilercontrol/commands/PrintTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/compilercontrol/commands/PrintTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -26,6 +26,7 @@
* @bug 8137167
* @summary Tests CompileCommand=print
* @library /testlibrary /test/lib /compiler/testlibrary ../share /
+ * @ignore 8140354
* @build compiler.compilercontrol.commands.PrintTest
* pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
* compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.*
--- a/hotspot/test/compiler/compilercontrol/directives/PrintTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/compilercontrol/directives/PrintTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -26,6 +26,7 @@
* @bug 8137167
* @summary Tests directives to be able to turn on print_assembly
* @library /testlibrary /test/lib /compiler/testlibrary ../share /
+ * @ignore 8140354
* @build compiler.compilercontrol.directives.PrintTest
* pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
* compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.*
--- a/hotspot/test/compiler/compilercontrol/jcmd/PrintDirectivesTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/compilercontrol/jcmd/PrintDirectivesTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -26,6 +26,7 @@
* @bug 8137167
* @summary Tests jcmd to be able to add a directive to compile only specified methods
* @library /testlibrary /test/lib /compiler/testlibrary ../share /
+ * @ignore 8140354
* @build compiler.compilercontrol.jcmd.PrintDirectivesTest
* pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
* compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.*
--- a/hotspot/test/compiler/compilercontrol/jcmd/StressAddMultiThreadedTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/compilercontrol/jcmd/StressAddMultiThreadedTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -27,6 +27,7 @@
* @summary Tests jcmd to be able to add a lot of huge directive files with
* parallel executed jcmds until timeout has reached
* @library /testlibrary /test/lib /compiler/testlibrary ../share /
+ * @ignore 8148563
* @build compiler.compilercontrol.jcmd.StressAddMultiThreadedTest
* pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
* compiler.testlibrary.CompilerUtils
--- a/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/compilercontrol/mixed/RandomValidCommandsTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -26,6 +26,7 @@
* @bug 8137167
* @summary Randomly generates valid commands with random types
* @library /testlibrary /test/lib /compiler/testlibrary ../share /
+ * @ignore 8140354
* @build compiler.compilercontrol.mixed.RandomValidCommandsTest
* pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
* compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.*
--- a/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -24,7 +24,7 @@
/**
* @test
* @bug 8057967
- * @run main/bootclasspath -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceClassUnloading
+ * @run main/bootclasspath -Xbatch -XX:+IgnoreUnrecognizedVMOptions -Xlog:classunload
* -XX:+PrintCompilation -XX:+TraceDependencies -XX:+TraceReferenceGC
* -verbose:gc java.lang.invoke.CallSiteDepContextTest
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/jsr292/LongReferenceCastingTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.lang.invoke.*;
+
+/**
+ * @test
+ * @bug 8148752
+ * @summary Test correct casting of MH arguments during inlining.
+ * @run main LongReferenceCastingTest
+ */
+public class LongReferenceCastingTest {
+ static final String MY_STRING = "myString";
+ static final MethodHandle MH;
+
+ static {
+ try {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ MethodType mt = MethodType.methodType(String.class, long.class, Object.class, String.class);
+ MH = lookup.findVirtual(LongReferenceCastingTest.class, "myMethod", mt);
+ } catch (Exception e) {
+ throw new Error(e);
+ }
+ }
+
+ public String myMethod(long l, Object o, String s) {
+ // The long argument occupies two stack slots, causing C2 to treat it as
+ // two arguments and casting the fist one two long and the second one to Object.
+ // As a result, Object o is casted to String and the o.toString() call is
+ // inlined as String::toString(). We fail at runtime because 'o' is not a String.
+ return o.toString();
+ }
+
+ public String toString() {
+ return MY_STRING;
+ }
+
+ public static void main(String[] args) throws Exception {
+ LongReferenceCastingTest test = new LongReferenceCastingTest();
+ try {
+ for (int i = 0; i < 20_000; ++i) {
+ if (!test.invoke().equals(MY_STRING)) {
+ throw new RuntimeException("Invalid string");
+ }
+ }
+ } catch (Throwable t) {
+ throw new RuntimeException("Test failed", t);
+ }
+ }
+
+ public String invoke() throws Throwable {
+ return (String) MH.invokeExact(this, 0L, (Object)this, MY_STRING);
+ }
+}
--- a/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/JVM_GetJVMCIRuntimeTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -35,6 +35,16 @@
* -Dcompiler.jvmci.JVM_GetJVMCIRuntimeTest.positive=false
* -XX:-EnableJVMCI
* compiler.jvmci.JVM_GetJVMCIRuntimeTest
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions
+ * -Dcompiler.jvmci.JVM_GetJVMCIRuntimeTest.positive=true
+ * -Dcompiler.jvmci.JVM_GetJVMCIRuntimeTest.threaded=true
+ * -XX:+EnableJVMCI
+ * compiler.jvmci.JVM_GetJVMCIRuntimeTest
+ * @run main/othervm -XX:+UnlockExperimentalVMOptions
+ * -Dcompiler.jvmci.JVM_GetJVMCIRuntimeTest.positive=false
+ * -Dcompiler.jvmci.JVM_GetJVMCIRuntimeTest.threaded=true
+ * -XX:-EnableJVMCI
+ * compiler.jvmci.JVM_GetJVMCIRuntimeTest
*/
@@ -43,22 +53,27 @@
import jdk.vm.ci.runtime.JVMCI;
import jdk.test.lib.Asserts;
-import java.lang.reflect.Method;
-
-public class JVM_GetJVMCIRuntimeTest {
+public class JVM_GetJVMCIRuntimeTest implements Runnable {
private static final boolean IS_POSITIVE = Boolean.getBoolean(
"compiler.jvmci.JVM_GetJVMCIRuntimeTest.positive");
-
- private final Method initializeRuntime;
+ private static final boolean IN_THREAD = Boolean.getBoolean(
+ "compiler.jvmci.JVM_GetJVMCIRuntimeTest.threaded");
- public static void main(String[] args) {
- new JVM_GetJVMCIRuntimeTest().runTest();
+ public static void main(String[] args) throws Throwable {
+ JVM_GetJVMCIRuntimeTest instance = new JVM_GetJVMCIRuntimeTest();
+ if (IN_THREAD) {
+ Thread t = new Thread(instance);
+ t.start();
+ t.join();
+ } else {
+ instance.run();
+ }
}
- private void runTest() {
+ public void run() {
Object result;
try {
- result = invoke();
+ result = JVMCI.getRuntime();
} catch (InternalError e) {
if (IS_POSITIVE) {
throw new AssertionError("unexpected exception", e);
@@ -70,28 +85,8 @@
}
Asserts.assertNotNull(result,
"initializeRuntime returned null");
- Asserts.assertEQ(result, invoke(),
+ Asserts.assertEQ(result, JVMCI.getRuntime(),
"initializeRuntime returns different results");
}
- private Object invoke() {
- Object result;
- try {
- result = initializeRuntime.invoke(JVMCI.class);
- } catch (ReflectiveOperationException e) {
- throw new Error("can't invoke initializeRuntime", e);
- }
- return result;
- }
-
- private JVM_GetJVMCIRuntimeTest() {
- Method method;
- try {
- method = JVMCI.class.getDeclaredMethod("initializeRuntime");
- method.setAccessible(true);
- } catch (NoSuchMethodException e) {
- throw new Error("can't find JVMCI::initializeRuntime", e);
- }
- initializeRuntime = method;
- }
}
--- a/hotspot/test/compiler/jvmci/code/CodeInstallationTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/code/CodeInstallationTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -92,6 +92,7 @@
asm.emitPrologue();
compiler.compile(asm);
+ asm.emitEpilogue();
HotSpotCompiledCode code = asm.finish(resolvedMethod);
InstalledCode installed = codeCache.addCode(resolvedMethod, code, null, null);
--- a/hotspot/test/compiler/jvmci/code/TestAssembler.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/code/TestAssembler.java Wed Jul 05 21:21:58 2017 +0200
@@ -32,11 +32,13 @@
import jdk.vm.ci.code.DebugInfo;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.site.Call;
import jdk.vm.ci.code.site.ConstantReference;
import jdk.vm.ci.code.site.DataPatch;
import jdk.vm.ci.code.site.DataSectionReference;
import jdk.vm.ci.code.site.Infopoint;
import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.code.site.Mark;
import jdk.vm.ci.code.site.Reference;
import jdk.vm.ci.code.site.Site;
import jdk.vm.ci.hotspot.HotSpotCompiledCode;
@@ -45,6 +47,7 @@
import jdk.vm.ci.hotspot.HotSpotConstant;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.Assumptions.Assumption;
+import jdk.vm.ci.meta.InvokeTarget;
import jdk.vm.ci.meta.LIRKind;
import jdk.vm.ci.meta.PlatformKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -61,6 +64,11 @@
public abstract void emitPrologue();
/**
+ * Emit the method epilogue code (e.g. the deopt handler).
+ */
+ public abstract void emitEpilogue();
+
+ /**
* Emit code to grow the stack frame.
*
* @param size the size in bytes that the stack should grow
@@ -181,6 +189,8 @@
private int stackAlignment;
private int curStackSlot;
+ private StackSlot deoptRescue;
+
protected TestAssembler(CodeCacheProvider codeCache, int initialFrameSize, int stackAlignment, PlatformKind narrowOopKind, Register... registers) {
this.narrowOopKind = LIRKind.reference(narrowOopKind);
@@ -216,6 +226,18 @@
return StackSlot.get(kind, -curStackSlot, true);
}
+ protected void setDeoptRescueSlot(StackSlot deoptRescue) {
+ this.deoptRescue = deoptRescue;
+ }
+
+ protected void recordCall(InvokeTarget target, int size, boolean direct, DebugInfo debugInfo) {
+ sites.add(new Call(target, code.position(), size, direct, debugInfo));
+ }
+
+ protected void recordMark(Object id) {
+ sites.add(new Mark(code.position(), id));
+ }
+
protected void recordImplicitException(DebugInfo info) {
sites.add(new Infopoint(code.position(), info, InfopointReason.IMPLICIT_EXCEPTION));
}
@@ -249,7 +271,7 @@
byte[] finishedData = data.finish();
DataPatch[] finishedDataPatches = dataPatches.toArray(new DataPatch[0]);
return new HotSpotCompiledNmethod(method.getName(), finishedCode, finishedCode.length, finishedSites, new Assumption[0], new ResolvedJavaMethod[]{method}, new Comment[0], finishedData, 16,
- finishedDataPatches, false, frameSize, 0, method, 0, id, 0L, false);
+ finishedDataPatches, false, frameSize, deoptRescue, method, 0, id, 0L, false);
}
protected static class Buffer {
--- a/hotspot/test/compiler/jvmci/code/amd64/AMD64TestAssembler.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/code/amd64/AMD64TestAssembler.java Wed Jul 05 21:21:58 2017 +0200
@@ -33,6 +33,8 @@
import jdk.vm.ci.code.site.DataSectionReference;
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.hotspot.HotSpotForeignCallTarget;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.LIRKind;
import jdk.vm.ci.meta.VMConstant;
@@ -63,6 +65,16 @@
emitFatNop();
code.emitByte(0x50 | AMD64.rbp.encoding); // PUSH rbp
emitMove(true, AMD64.rbp, AMD64.rsp); // MOV rbp, rsp
+ setDeoptRescueSlot(newStackSlot(LIRKind.value(AMD64Kind.QWORD)));
+ }
+
+ @Override
+ public void emitEpilogue() {
+ HotSpotVMConfig config = HotSpotVMConfig.config();
+ recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
+ recordCall(new HotSpotForeignCallTarget(config.handleDeoptStub), 5, true, null);
+ code.emitByte(0xE8); // CALL rel32
+ code.emitInt(0xDEADDEAD);
}
@Override
--- a/hotspot/test/compiler/jvmci/code/sparc/SPARCTestAssembler.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/code/sparc/SPARCTestAssembler.java Wed Jul 05 21:21:58 2017 +0200
@@ -32,7 +32,9 @@
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
import jdk.vm.ci.hotspot.HotSpotCompiledCode;
import jdk.vm.ci.hotspot.HotSpotConstant;
+import jdk.vm.ci.hotspot.HotSpotForeignCallTarget;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
+import jdk.vm.ci.hotspot.HotSpotVMConfig;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.LIRKind;
import jdk.vm.ci.meta.VMConstant;
@@ -68,6 +70,15 @@
@Override
public void emitPrologue() {
emitOp3(0b10, SPARC.sp, 0b111100, SPARC.sp, -SPARC.REGISTER_SAFE_AREA_SIZE); // SAVE sp, -128, sp
+ setDeoptRescueSlot(newStackSlot(LIRKind.value(SPARCKind.XWORD)));
+ }
+
+ @Override
+ public void emitEpilogue() {
+ HotSpotVMConfig config = HotSpotVMConfig.config();
+ recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
+ recordCall(new HotSpotForeignCallTarget(config.handleDeoptStub), 4, true, null);
+ code.emitInt(1 << 30); // CALL
}
@Override
--- a/hotspot/test/compiler/jvmci/errors/CodeInstallerTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/errors/CodeInstallerTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -28,6 +28,7 @@
import jdk.vm.ci.code.Architecture;
import jdk.vm.ci.code.CodeCacheProvider;
import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.DataPatch;
import jdk.vm.ci.code.site.Site;
import jdk.vm.ci.hotspot.HotSpotCompiledCode;
@@ -71,9 +72,9 @@
dummyMethod = metaAccess.lookupJavaMethod(method);
}
- protected void installEmptyCode(Site[] sites, Assumption[] assumptions, Comment[] comments, int dataSectionAlignment, DataPatch[] dataSectionPatches) {
+ protected void installEmptyCode(Site[] sites, Assumption[] assumptions, Comment[] comments, int dataSectionAlignment, DataPatch[] dataSectionPatches, StackSlot deoptRescueSlot) {
HotSpotCompiledCode code = new HotSpotCompiledCode("dummyMethod", new byte[0], 0, sites, assumptions, new ResolvedJavaMethod[]{dummyMethod}, comments, new byte[8], dataSectionAlignment,
- dataSectionPatches, false, 0, 0);
+ dataSectionPatches, false, 0, deoptRescueSlot);
codeCache.addCode(dummyMethod, code, null, null);
}
--- a/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/errors/TestInvalidCompilationResult.java Wed Jul 05 21:21:58 2017 +0200
@@ -30,6 +30,7 @@
package compiler.jvmci.errors;
+import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.ConstantReference;
import jdk.vm.ci.code.site.DataPatch;
import jdk.vm.ci.code.site.DataSectionReference;
@@ -80,104 +81,111 @@
@Test(expected = JVMCIError.class)
public void testInvalidAssumption() {
- installEmptyCode(new Site[0], new Assumption[]{new InvalidAssumption()}, new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[0], new Assumption[]{new InvalidAssumption()}, new Comment[0], 16, new DataPatch[0], null);
}
@Test(expected = JVMCIError.class)
public void testInvalidAlignment() {
- installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 7, new DataPatch[0]);
+ installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 7, new DataPatch[0], null);
}
@Test(expected = NullPointerException.class)
public void testNullDataPatchInDataSection() {
- installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{null});
+ installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{null}, null);
}
@Test(expected = NullPointerException.class)
public void testNullReferenceInDataSection() {
- installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{new DataPatch(0, null)});
+ installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{new DataPatch(0, null)}, null);
}
@Test(expected = JVMCIError.class)
public void testInvalidDataSectionReference() {
DataSectionReference ref = new DataSectionReference();
ref.setOffset(0);
- installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{new DataPatch(0, ref)});
+ installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{new DataPatch(0, ref)}, null);
}
@Test(expected = JVMCIError.class)
public void testInvalidNarrowMethodInDataSection() {
HotSpotConstant c = (HotSpotConstant) dummyMethod.getEncoding();
ConstantReference ref = new ConstantReference((VMConstant) c.compress());
- installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{new DataPatch(0, ref)});
+ installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{new DataPatch(0, ref)}, null);
}
@Test(expected = NullPointerException.class)
public void testNullConstantInDataSection() {
ConstantReference ref = new ConstantReference(null);
- installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{new DataPatch(0, ref)});
+ installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{new DataPatch(0, ref)}, null);
}
@Test(expected = JVMCIError.class)
public void testInvalidConstantInDataSection() {
ConstantReference ref = new ConstantReference(new InvalidVMConstant());
- installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{new DataPatch(0, ref)});
+ installEmptyCode(new Site[0], new Assumption[0], new Comment[0], 16, new DataPatch[]{new DataPatch(0, ref)}, null);
}
@Test(expected = NullPointerException.class)
public void testNullReferenceInCode() {
- installEmptyCode(new Site[]{new DataPatch(0, null)}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{new DataPatch(0, null)}, new Assumption[0], new Comment[0], 16, new DataPatch[0], null);
}
@Test(expected = NullPointerException.class)
public void testNullConstantInCode() {
ConstantReference ref = new ConstantReference(null);
- installEmptyCode(new Site[]{new DataPatch(0, ref)}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{new DataPatch(0, ref)}, new Assumption[0], new Comment[0], 16, new DataPatch[0], null);
}
@Test(expected = JVMCIError.class)
public void testInvalidConstantInCode() {
ConstantReference ref = new ConstantReference(new InvalidVMConstant());
- installEmptyCode(new Site[]{new DataPatch(0, ref)}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{new DataPatch(0, ref)}, new Assumption[0], new Comment[0], 16, new DataPatch[0], null);
}
@Test(expected = JVMCIError.class)
public void testInvalidReference() {
InvalidReference ref = new InvalidReference();
- installEmptyCode(new Site[]{new DataPatch(0, ref)}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{new DataPatch(0, ref)}, new Assumption[0], new Comment[0], 16, new DataPatch[0], null);
}
@Test(expected = JVMCIError.class)
public void testOutOfBoundsDataSectionReference() {
DataSectionReference ref = new DataSectionReference();
ref.setOffset(0x1000);
- installEmptyCode(new Site[]{new DataPatch(0, ref)}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{new DataPatch(0, ref)}, new Assumption[0], new Comment[0], 16, new DataPatch[0], null);
}
@Test(expected = JVMCIError.class)
public void testInvalidMark() {
- installEmptyCode(new Site[]{new Mark(0, new Object())}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{new Mark(0, new Object())}, new Assumption[0], new Comment[0], 16, new DataPatch[0], null);
}
@Test(expected = JVMCIError.class)
public void testInvalidMarkInt() {
- installEmptyCode(new Site[]{new Mark(0, -1)}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{new Mark(0, -1)}, new Assumption[0], new Comment[0], 16, new DataPatch[0], null);
}
@Test(expected = NullPointerException.class)
public void testNullSite() {
- installEmptyCode(new Site[]{null}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{null}, new Assumption[0], new Comment[0], 16, new DataPatch[0], null);
}
@Test(expected = JVMCIError.class)
public void testInfopointMissingDebugInfo() {
Infopoint info = new Infopoint(0, null, InfopointReason.METHOD_START);
- installEmptyCode(new Site[]{info}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{info}, new Assumption[0], new Comment[0], 16, new DataPatch[0], null);
}
@Test(expected = JVMCIError.class)
public void testSafepointMissingDebugInfo() {
Infopoint info = new Infopoint(0, null, InfopointReason.SAFEPOINT);
- installEmptyCode(new Site[]{info}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ StackSlot deoptRescueSlot = StackSlot.get(null, 0, true);
+ installEmptyCode(new Site[]{info}, new Assumption[0], new Comment[0], 16, new DataPatch[0], deoptRescueSlot);
+ }
+
+ @Test(expected = JVMCIError.class)
+ public void testInvalidDeoptRescueSlot() {
+ StackSlot deoptRescueSlot = StackSlot.get(null, -1, false);
+ installEmptyCode(new Site[]{}, new Assumption[0], new Comment[0], 16, new DataPatch[0], deoptRescueSlot);
}
}
--- a/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/errors/TestInvalidDebugInfo.java Wed Jul 05 21:21:58 2017 +0200
@@ -66,10 +66,14 @@
}
private void test(VirtualObject[] vobj, JavaValue[] values, JavaKind[] slotKinds, int locals, int stack, int locks) {
+ test(vobj, values, slotKinds, locals, stack, locks, StackSlot.get(null, 0, true));
+ }
+
+ private void test(VirtualObject[] vobj, JavaValue[] values, JavaKind[] slotKinds, int locals, int stack, int locks, StackSlot deoptRescueSlot) {
BytecodeFrame frame = new BytecodeFrame(null, dummyMethod, 0, false, false, values, slotKinds, locals, stack, locks);
DebugInfo info = new DebugInfo(frame, vobj);
info.setReferenceMap(new HotSpotReferenceMap(new Location[0], new Location[0], new int[0], 8));
- installEmptyCode(new Site[]{new Infopoint(0, info, InfopointReason.SAFEPOINT)}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{new Infopoint(0, info, InfopointReason.SAFEPOINT)}, new Assumption[0], new Comment[0], 16, new DataPatch[0], deoptRescueSlot);
}
@Test(expected = NullPointerException.class)
@@ -83,6 +87,11 @@
}
@Test(expected = JVMCIError.class)
+ public void testMissingDeoptRescueSlot() {
+ test(null, new JavaValue[0], new JavaKind[0], 0, 0, 0, null);
+ }
+
+ @Test(expected = JVMCIError.class)
public void testUnexpectedScopeValuesLength() {
test(new JavaValue[]{JavaConstant.FALSE}, new JavaKind[0], 0, 0, 0);
}
--- a/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/errors/TestInvalidOopMap.java Wed Jul 05 21:21:58 2017 +0200
@@ -35,6 +35,7 @@
import jdk.vm.ci.code.Location;
import jdk.vm.ci.code.ReferenceMap;
import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.DataPatch;
import jdk.vm.ci.code.site.Infopoint;
import jdk.vm.ci.code.site.InfopointReason;
@@ -61,7 +62,7 @@
BytecodePosition pos = new BytecodePosition(null, dummyMethod, 0);
DebugInfo info = new DebugInfo(pos);
info.setReferenceMap(refMap);
- installEmptyCode(new Site[]{new Infopoint(0, info, InfopointReason.SAFEPOINT)}, new Assumption[0], new Comment[0], 16, new DataPatch[0]);
+ installEmptyCode(new Site[]{new Infopoint(0, info, InfopointReason.SAFEPOINT)}, new Assumption[0], new Comment[0], 16, new DataPatch[0], StackSlot.get(null, 0, true));
}
@Test(expected = NullPointerException.class)
--- a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -109,7 +109,7 @@
.getResolvedMethod(SimpleClass.class, testMethod);
HotSpotCompiledCode compiledCode = new HotSpotCompiledCode(METHOD_NAME, new byte[0], 0, new Site[0],
new Assumption[0], new ResolvedJavaMethod[]{method}, new Comment[0], new byte[0], 16,
- new DataPatch[0], false, 0, 0);
+ new DataPatch[0], false, 0, null);
codeCache.installCode(method, compiledCode, /* installedCode = */ null, /* speculationLog = */ null,
/* isDefault = */ false);
Asserts.assertEQ(gotInstallNotification, 1,
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/NameAndSignature.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/NameAndSignature.java Wed Jul 05 21:21:58 2017 +0200
@@ -39,7 +39,7 @@
final Class<?> returnType;
final Class<?>[] parameterTypes;
- public NameAndSignature(Method m) {
+ NameAndSignature(Method m) {
this.name = m.getName();
this.returnType = m.getReturnType();
this.parameterTypes = m.getParameterTypes();
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java Wed Jul 05 21:21:58 2017 +0200
@@ -47,7 +47,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -501,7 +500,7 @@
final Method implementation;
final Set<Method> declarations;
- public Declarations(Method impl) {
+ Declarations(Method impl) {
this.implementation = impl;
declarations = new HashSet<>();
}
@@ -850,23 +849,6 @@
}
@Test
- public void classFilePathTest() {
- for (Class<?> c : classes) {
- ResolvedJavaType type = metaAccess.lookupJavaType(c);
- URL path = type.getClassFilePath();
- if (type.isPrimitive() || type.isArray()) {
- assertEquals(null, path);
- } else {
- assertNotNull(path);
- String pathString = path.getPath();
- if (type.isLocal() || type.isMember()) {
- assertTrue(pathString.indexOf('$') > 0);
- }
- }
- }
- }
-
- @Test
public void isTrustedInterfaceTypeTest() {
for (Class<?> c : classes) {
ResolvedJavaType type = metaAccess.lookupJavaType(c);
--- a/hotspot/test/compiler/runtime/safepoints/TestRegisterRestoring.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/compiler/runtime/safepoints/TestRegisterRestoring.java Wed Jul 05 21:21:58 2017 +0200
@@ -27,7 +27,7 @@
* @test
* @bug 8148490
* @summary Test correct saving and restoring of vector registers at safepoints.
- * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:CompileCommand=exclude,TestRegisterRestoring::main -XX:+SafepointALot TestRegisterRestoring
+ * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:-TieredCompilation -XX:CompileCommand=exclude,TestRegisterRestoring::main -XX:+SafepointALot TestRegisterRestoring
*/
public class TestRegisterRestoring {
public static void main(String args[]) throws Exception {
--- a/hotspot/test/gc/arguments/TestSelectDefaultGC.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/gc/arguments/TestSelectDefaultGC.java Wed Jul 05 21:21:58 2017 +0200
@@ -29,6 +29,7 @@
* @library /testlibrary
* @modules java.base/sun.misc
* java.management
+ * @ignore 8148239
* @run driver TestSelectDefaultGC
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/cms/TestBubbleUpRef.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/*
+ * @test
+ * @requires vm.gc=="ConcMarkSweep" | vm.gc == "null"
+ * @key cte_test
+ * @bug 4950157
+ * @summary Stress the behavior of ergonomics when the heap is nearly full and
+ * stays nearly full.
+ * @run main/othervm
+ * -XX:+UseConcMarkSweepGC -XX:-CMSYield -XX:-CMSPrecleanRefLists1
+ * -XX:CMSInitiatingOccupancyFraction=0 -Xmx8m TestBubbleUpRef 16000 50 10000
+ */
+
+/**
+ * Test program to stress the behavior of ergonomics when the
+ * heap is nearly full and stays nearly full.
+ * This is a test to catch references that have been discovered
+ * during concurrent marking and whose referents have been
+ * cleared by the mutator.
+ * Allocate objects with weak references until the heap is full
+ * Free the objects.
+ * Do work so that concurrent marking has a chance to work
+ * Clear the referents out of the weak references
+ * System.gc() in the hopes that it will acquire the collection
+ * Free the weak references
+ * Do it again.
+ *
+ * Use the following VM options
+ * -Xmx8m -XX:-CMSYield [-XX:+UseConcMarkSweepGC] -XX:-CMSPrecleanRefLists1
+ * -XX:CMSInitiatingOccupancyFraction=0
+ *
+ * Use parameter:
+ * args[0] - array size (16000)
+ * args[1] - iterations (50)
+ * args[2] - work (10000)
+ */
+class MyList extends LinkedList {
+
+ int[] a;
+
+ MyList(int size) {
+ a = new int[size];
+ }
+}
+
+class MyRefList extends LinkedList {
+
+ WeakReference ref;
+
+ MyRefList(Object o, ReferenceQueue rq) {
+ ref = new WeakReference(o, rq);
+ }
+
+ void clearReferent() {
+ ref.clear();
+ }
+}
+
+public class TestBubbleUpRef {
+
+ MyList list;
+ MyRefList refList;
+ ReferenceQueue rq;
+ int refListLen;
+ int arraySize;
+ int iterations;
+ int workUnits;
+
+ TestBubbleUpRef(int as, int cnt, int wk) {
+ arraySize = as;
+ iterations = cnt;
+ workUnits = wk;
+ list = new MyList(arraySize);
+ refList = new MyRefList(list, rq);
+ }
+
+ public void fill() {
+ System.out.println("fill() " + iterations + " times");
+ int count = 0;
+ while (true) {
+ try {
+ // Allocations
+ MyList next = new MyList(arraySize);
+ list.add(next);
+ MyRefList nextRef = new MyRefList(next, rq);
+ refList.add(nextRef);
+ } catch (OutOfMemoryError e) {
+ // When the heap is full
+ try {
+ if (count++ > iterations) {
+ return;
+ }
+ System.out.println("Freeing list");
+ while (!list.isEmpty()) {
+ list.removeFirst();
+ }
+ System.out.println("Doing work");
+ int j = 0;
+ for (int i = 1; i < workUnits; i++) {
+ j = j + i;
+ }
+ System.out.println("Clearing refs");
+ ListIterator listIt = refList.listIterator();
+ while (listIt.hasNext()) {
+ MyRefList next = (MyRefList) listIt.next();
+ next.clearReferent();
+ }
+ System.gc();
+ System.out.println("Freeing refs");
+ while (!refList.isEmpty()) {
+ refList.removeFirst();
+ }
+ } catch (OutOfMemoryError e2) {
+ System.err.println("Out of Memory - 2 ");
+ continue;
+ }
+ } catch (Exception e) {
+ System.err.println("Unexpected exception: " + e);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Test entry point.
+ * args[0] - array size (is the size of the int array in a list item)
+ * args[1] - iterations (is the number of out-of-memory exceptions before exit)
+ * args[2] - work (is the work done between allocations)
+ * @param args
+ */
+ public static void main(String[] args) {
+ // Get the input parameters.
+ if (args.length != 3) {
+ throw new IllegalArgumentException("Wrong number of input argumets");
+ }
+
+ int as = Integer.parseInt(args[0]);
+ int cnt = Integer.parseInt(args[1]);
+ int work = Integer.parseInt(args[2]);
+
+ System.out.println("<array size> " + as + "\n"
+ + "<OOM's> " + cnt + "\n"
+ + "<work units> " + work + "\n");
+
+ // Initialization
+ TestBubbleUpRef b = new TestBubbleUpRef(as, cnt, work);
+
+ // Run the test
+ try {
+ b.fill();
+ } catch (OutOfMemoryError e) {
+ b = null; // Free memory before trying to print anything
+ System.err.println("Out of Memory - exiting ");
+ } catch (Exception e) {
+ System.err.println("Exiting ");
+ }
+ }
+}
+
--- a/hotspot/test/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, 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
@@ -38,34 +38,6 @@
public class TestG1TraceEagerReclaimHumongousObjects {
public static void main(String[] args) throws Exception {
- testGCLogs();
- testHumongousObjectGCLogs();
- }
-
- private static void testGCLogs() throws Exception {
-
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
- "-Xms128M",
- "-Xmx128M",
- "-Xmn16M",
- "-XX:G1HeapRegionSize=1M",
- "-Xlog:gc+phases=trace",
- "-XX:+UnlockExperimentalVMOptions",
- GCTest.class.getName());
-
- OutputAnalyzer output = new OutputAnalyzer(pb.start());
-
- // As G1EagerReclaimHumongousObjects is set(default), below logs should be displayed.
- // And GCTest doesn't have humongous objects, so values should be zero.
- output.shouldContain("Humongous Reclaim");
- output.shouldContain("Humongous Total: 0");
- output.shouldContain("Humongous Candidate: 0");
- output.shouldContain("Humongous Reclaimed: 0");
-
- output.shouldHaveExitValue(0);
- }
-
- private static void testHumongousObjectGCLogs() throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
"-Xms128M",
"-Xmx128M",
@@ -90,19 +62,6 @@
output.shouldHaveExitValue(0);
}
- static class GCTest {
- private static byte[] garbage;
-
- public static void main(String [] args) {
- System.out.println("Creating garbage");
- // create 128MB of garbage. This should result in at least one GC
- for (int i = 0; i < 1024; i++) {
- garbage = new byte[128 * 1024];
- }
- System.out.println("Done");
- }
- }
-
static class GCWithHumongousObjectTest {
public static final int M = 1024*1024;
--- a/hotspot/test/gc/g1/TestRemsetLoggingTools.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/gc/g1/TestRemsetLoggingTools.java Wed Jul 05 21:21:58 2017 +0200
@@ -96,7 +96,7 @@
public static void expectPerRegionRSetSummaries(String result, int expectedCumulative, int expectedPeriodic) throws Exception {
expectRSetSummaries(result, expectedCumulative, expectedPeriodic);
int actualYoung = result.split("Young regions").length - 1;
- int actualHumonguous = result.split("Humonguous regions").length - 1;
+ int actualHumongous = result.split("Humongous regions").length - 1;
int actualFree = result.split("Free regions").length - 1;
int actualOther = result.split("Old regions").length - 1;
@@ -104,7 +104,7 @@
int expectedPerRegionTypeInfo = (expectedCumulative + expectedPeriodic) * 4;
checkCounts(expectedPerRegionTypeInfo, actualYoung, "Young");
- checkCounts(expectedPerRegionTypeInfo, actualHumonguous, "Humonguous");
+ checkCounts(expectedPerRegionTypeInfo, actualHumongous, "Humongous");
checkCounts(expectedPerRegionTypeInfo, actualFree, "Free");
checkCounts(expectedPerRegionTypeInfo, actualOther, "Old");
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/humongousObjects/TestHeapCounters.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package gc.g1.humongousObjects;
+
+import gc.testlibrary.Helpers;
+import jdk.test.lib.Asserts;
+import sun.hotspot.WhiteBox;
+
+import java.lang.management.GarbageCollectorMXBean;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @test TestHeapCounters
+ * @summary Checks that heap counters work as expected after humongous allocations/deallocations
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @library /testlibrary /test/lib /
+ * @modules java.management
+ * @build sun.hotspot.WhiteBox
+ * gc.testlibrary.Helpers
+ * gc.g1.humongousObjects.TestHeapCounters
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ *
+ * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * -Xmx128m -Xms128m
+ * -XX:G1HeapRegionSize=1M -XX:InitiatingHeapOccupancyPercent=100 -XX:-G1UseAdaptiveIHOP
+ * -Xlog:gc -Xlog:gc:file=TestHeapCountersRuntime.gc.log
+ * gc.g1.humongousObjects.TestHeapCounters RUNTIME_COUNTER
+ *
+ * @run main/othervm -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ * -Xmx128m -Xms128m
+ * -XX:G1HeapRegionSize=1M -XX:InitiatingHeapOccupancyPercent=100 -XX:-G1UseAdaptiveIHOP
+ * -Xlog:gc -Xlog:gc:file=TestHeapCountersMXBean.gc.log
+ * gc.g1.humongousObjects.TestHeapCounters MX_BEAN_COUNTER
+ */
+public class TestHeapCounters {
+ private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+ private static final int G1_REGION_SIZE = WHITE_BOX.g1RegionSize();
+ private static final int HALF_G1_REGION_SIZE = G1_REGION_SIZE / 2;
+
+ // Since during deallocation GC could free (very unlikely) some non-humongous data this value relaxes amount of
+ // memory we expect to be freed.
+ private static final double ALLOCATION_SIZE_TOLERANCE_FACTOR = 0.85D;
+
+ private enum MemoryCounter {
+ MX_BEAN_COUNTER {
+ @Override
+ public long getUsedMemory() {
+ return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed();
+ }
+ },
+ RUNTIME_COUNTER {
+ @Override
+ public long getUsedMemory() {
+ return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+ }
+ };
+
+ public abstract long getUsedMemory();
+ }
+
+ private static class Allocation {
+ private byte[] allocation;
+ public final long expectedSize;
+
+ public Allocation(int allocationSize, long allocationExpectedSize) {
+ allocation = new byte[allocationSize];
+ expectedSize = allocationExpectedSize;
+
+ System.out.println(String.format("Object size is %d; Object is %shumongous",
+ WHITE_BOX.getObjectSize(allocation),
+ (WHITE_BOX.g1IsHumongous(allocation) ? "" : "non-")));
+
+ selfTest();
+ }
+
+ private void selfTest() {
+ boolean isHumongous = WHITE_BOX.getObjectSize(allocation) > HALF_G1_REGION_SIZE;
+ boolean shouldBeHumongous = WHITE_BOX.g1IsHumongous(allocation);
+
+ // Sanity check
+ Asserts.assertEquals(isHumongous, shouldBeHumongous,
+ String.format("Test Bug: Object of size %d is expected to be %shumongous but it is not",
+ WHITE_BOX.getObjectSize(allocation), (shouldBeHumongous ? "" : "non-")));
+ }
+
+ public void forgetAllocation() {
+ allocation = null;
+ }
+ }
+
+ public static void main(String[] args) {
+
+ if (args.length != 1) {
+ throw new Error("Expected memory counter name wasn't provided as command line argument");
+ }
+ MemoryCounter memoryCounter = MemoryCounter.valueOf(args[0].toUpperCase());
+
+ int byteArrayMemoryOverhead = Helpers.detectByteArrayAllocationOverhead();
+
+ // Largest non-humongous byte[]
+ int maxByteArrayNonHumongousSize = HALF_G1_REGION_SIZE - byteArrayMemoryOverhead;
+
+ // Maximum byte[] that takes one region
+ int maxByteArrayOneRegionSize = G1_REGION_SIZE - byteArrayMemoryOverhead;
+
+ List<Integer> allocationSizes = Arrays.asList(
+ (int) maxByteArrayNonHumongousSize + 1,
+ (int) (0.8f * maxByteArrayOneRegionSize),
+ (int) (maxByteArrayOneRegionSize),
+ (int) (1.2f * maxByteArrayOneRegionSize),
+ (int) (1.5f * maxByteArrayOneRegionSize),
+ (int) (1.7f * maxByteArrayOneRegionSize),
+ (int) (2.0f * maxByteArrayOneRegionSize),
+ (int) (2.5f * maxByteArrayOneRegionSize)
+ );
+
+ List<Allocation> allocations = new ArrayList<>();
+ List<GarbageCollectorMXBean> gcBeans =
+ ManagementFactory.getGarbageCollectorMXBeans();
+
+ long gcCountBefore = gcBeans.stream().mapToLong(GarbageCollectorMXBean::getCollectionCount).sum();
+
+
+ System.out.println("Starting allocations - no GC should happen until we finish them");
+
+ for (int allocationSize : allocationSizes) {
+
+ long usedMemoryBefore = memoryCounter.getUsedMemory();
+ long expectedAllocationSize = (long) Math.ceil((double) allocationSize / G1_REGION_SIZE) * G1_REGION_SIZE;
+ allocations.add(new Allocation(allocationSize, expectedAllocationSize));
+ long usedMemoryAfter = memoryCounter.getUsedMemory();
+
+ System.out.format("Expected allocation size: %d\nUsed memory before allocation: %d\n"
+ + "Used memory after allocation: %d\n",
+ expectedAllocationSize, usedMemoryBefore, usedMemoryAfter);
+
+ long gcCountNow = gcBeans.stream().mapToLong(GarbageCollectorMXBean::getCollectionCount).sum();
+
+ if (gcCountNow == gcCountBefore) {
+ // We should allocate at least allocation.expectedSize
+ Asserts.assertGreaterThanOrEqual(usedMemoryAfter - usedMemoryBefore, expectedAllocationSize,
+ "Counter of type " + memoryCounter.getClass().getSimpleName() +
+ " returned wrong allocation size");
+ } else {
+ System.out.println("GC happened during allocation so the check is skipped");
+ gcCountBefore = gcCountNow;
+ }
+ }
+
+ System.out.println("Finished allocations - no GC should have happened before this line");
+
+
+ allocations.stream().forEach(allocation -> {
+ long usedMemoryBefore = memoryCounter.getUsedMemory();
+ allocation.forgetAllocation();
+
+ WHITE_BOX.fullGC();
+
+ long usedMemoryAfter = memoryCounter.getUsedMemory();
+
+ // We should free at least allocation.expectedSize * ALLOCATION_SIZE_TOLERANCE_FACTOR
+ Asserts.assertGreaterThanOrEqual(usedMemoryBefore - usedMemoryAfter,
+ (long) (allocation.expectedSize * ALLOCATION_SIZE_TOLERANCE_FACTOR),
+ "Counter of type " + memoryCounter.getClass().getSimpleName() + " returned wrong allocation size");
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/TestPLABPromotion.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2016, 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 TestPLABPromotion
+ * @bug 8141278
+ * @summary Test PLAB promotion
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @requires vm.opt.FlightRecorder != true
+ * @library /testlibrary /../../test/lib /
+ * @modules java.management
+ * @build ClassFileInstaller
+ * sun.hotspot.WhiteBox
+ * gc.g1.plab.lib.MemoryConsumer
+ * gc.g1.plab.lib.LogParser
+ * gc.g1.plab.lib.AppPLABPromotion
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/timeout=240 gc.g1.plab.TestPLABPromotion
+ */
+package gc.g1.plab;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Arrays;
+import java.io.PrintStream;
+
+import gc.g1.plab.lib.AppPLABPromotion;
+import gc.g1.plab.lib.LogParser;
+import gc.g1.plab.lib.PLABUtils;
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Platform;
+
+/**
+ * Test checks PLAB promotion of different size objects.
+ */
+public class TestPLABPromotion {
+
+ // GC ID with survivor PLAB statistics
+ private final static long GC_ID_SURVIVOR_STATS = 1l;
+ // GC ID with old PLAB statistics
+ private final static long GC_ID_OLD_STATS = 2l;
+
+ // Allowable difference for memory consumption (percentage)
+ private final static long MEM_DIFFERENCE_PCT = 5;
+
+ private static final int PLAB_SIZE_SMALL = 1024;
+ private static final int PLAB_SIZE_MEDIUM = 4096;
+ private static final int PLAB_SIZE_HIGH = 65536;
+ private static final int OBJECT_SIZE_SMALL = 10;
+ private static final int OBJECT_SIZE_MEDIUM = 100;
+ private static final int OBJECT_SIZE_HIGH = 1000;
+ private static final int GC_NUM_SMALL = 1;
+ private static final int GC_NUM_MEDIUM = 3;
+ private static final int GC_NUM_HIGH = 7;
+ private static final int WASTE_PCT_SMALL = 10;
+ private static final int WASTE_PCT_MEDIUM = 20;
+ private static final int WASTE_PCT_HIGH = 30;
+ private static final int YOUNG_SIZE_LOW = 16;
+ private static final int YOUNG_SIZE_HIGH = 64;
+ private static final boolean PLAB_FIXED = true;
+ private static final boolean PLAB_DYNAMIC = false;
+
+ private final static TestCase[] TEST_CASES = {
+ // Test cases for unreachable object, PLAB size is fixed
+ new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_FIXED, false, false),
+ new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_FIXED, false, false),
+ // Test cases for reachable objects, PLAB size is fixed
+ new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_SMALL, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_FIXED, true, true),
+ new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_MEDIUM, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_FIXED, true, true),
+ new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_SMALL, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_FIXED, true, false),
+ new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_FIXED, true, true),
+ new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_FIXED, true, true),
+ new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_FIXED, true, true),
+ new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_SMALL, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_FIXED, true, true),
+ new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_FIXED, true, true),
+ new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_SMALL, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, YOUNG_SIZE_HIGH, PLAB_FIXED, true, false),
+ // Test cases for unreachable object, PLAB size is not fixed
+ new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_LOW, PLAB_DYNAMIC, false, false),
+ // Test cases for reachable objects, PLAB size is not fixed
+ new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, true),
+ new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_SMALL, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true),
+ new TestCase(WASTE_PCT_SMALL, PLAB_SIZE_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_HIGH, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, false),
+ new TestCase(WASTE_PCT_MEDIUM, PLAB_SIZE_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_MEDIUM, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true),
+ new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, YOUNG_SIZE_HIGH, PLAB_DYNAMIC, true, true),
+ new TestCase(WASTE_PCT_HIGH, PLAB_SIZE_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, YOUNG_SIZE_LOW, PLAB_DYNAMIC, true, true)
+ };
+
+ public static void main(String[] args) throws Throwable {
+
+ for (TestCase testCase : TEST_CASES) {
+ // What we going to check.
+ testCase.print(System.out);
+ List<String> options = PLABUtils.prepareOptions(testCase.toOptions());
+ options.add(AppPLABPromotion.class.getName());
+ OutputAnalyzer out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()]));
+ if (out.getExitValue() != 0) {
+ System.out.println(out.getOutput());
+ throw new RuntimeException("Expect exit code 0.");
+ }
+ checkResults(out.getOutput(), testCase);
+ }
+ }
+
+ private static void checkResults(String output, TestCase testCase) {
+ long plabAllocatedSurvivor;
+ long directAllocatedSurvivor;
+ long plabAllocatedOld;
+ long directAllocatedOld;
+ long memAllocated = testCase.getMemToFill();
+ long wordSize = Platform.is32bit() ? 4l : 8l;
+ LogParser logParser = new LogParser(output);
+
+ Map<String, Long> survivorStats = getPlabStats(logParser, LogParser.ReportType.SURVIVOR_STATS, GC_ID_SURVIVOR_STATS);
+ Map<String, Long> oldStats = getPlabStats(logParser, LogParser.ReportType.OLD_STATS, GC_ID_OLD_STATS);
+
+ plabAllocatedSurvivor = wordSize * survivorStats.get("used");
+ directAllocatedSurvivor = wordSize * survivorStats.get("direct_allocated");
+ plabAllocatedOld = wordSize * oldStats.get("used");
+ directAllocatedOld = wordSize * oldStats.get("direct_allocated");
+
+ System.out.printf("Survivor PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated);
+ System.out.printf("Old PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedOld, directAllocatedOld, memAllocated);
+
+ // Unreachable objects case
+ if (testCase.isDeadObjectCase()) {
+ // No dead objects should be promoted
+ if (!(checkRatio(plabAllocatedSurvivor, memAllocated) && checkRatio(directAllocatedSurvivor, memAllocated))) {
+ System.out.println(output);
+ throw new RuntimeException("Unreachable objects should not be allocated using PLAB or direct allocated to Survivor");
+ }
+ if (!(checkRatio(plabAllocatedOld, memAllocated) && checkRatio(directAllocatedOld, memAllocated))) {
+ System.out.println(output);
+ throw new RuntimeException("Unreachable objects should not be allocated using PLAB or direct allocated to Old");
+ }
+ } else {
+ // Live objects case
+ if (testCase.isPromotedByPLAB()) {
+ // All live small objects should be promoted using PLAB
+ if (!checkDifferenceRatio(plabAllocatedSurvivor, memAllocated)) {
+ System.out.println(output);
+ throw new RuntimeException("Expect that Survivor PLAB allocation are similar to all mem consumed");
+ }
+ if (!checkDifferenceRatio(plabAllocatedOld, memAllocated)) {
+ System.out.println(output);
+ throw new RuntimeException("Expect that Old PLAB allocation are similar to all mem consumed");
+ }
+ } else {
+ // All big objects should be directly allocated
+ if (!checkDifferenceRatio(directAllocatedSurvivor, memAllocated)) {
+ System.out.println(output);
+ throw new RuntimeException("Test fails. Expect that Survivor direct allocation are similar to all mem consumed");
+ }
+ if (!checkDifferenceRatio(directAllocatedOld, memAllocated)) {
+ System.out.println(output);
+ throw new RuntimeException("Test fails. Expect that Old direct allocation are similar to all mem consumed");
+ }
+ }
+
+ // All promoted objects size should be similar to all consumed memory
+ if (!checkDifferenceRatio(plabAllocatedSurvivor + directAllocatedSurvivor, memAllocated)) {
+ System.out.println(output);
+ throw new RuntimeException("Test fails. Expect that Survivor gen total allocation are similar to all mem consumed");
+ }
+ if (!checkDifferenceRatio(plabAllocatedOld + directAllocatedOld, memAllocated)) {
+ System.out.println(output);
+ throw new RuntimeException("Test fails. Expect that Old gen total allocation are similar to all mem consumed");
+ }
+ }
+ System.out.println("Test passed!");
+ }
+
+ /**
+ * Returns true if checkedValue is less than MEM_DIFFERENCE_PCT percent of controlValue.
+ *
+ * @param checkedValue - checked value
+ * @param controlValue - referent value
+ * @return true if checkedValue is less than MEM_DIFFERENCE_PCT percent of controlValue
+ */
+ private static boolean checkRatio(long checkedValue, long controlValue) {
+ return (Math.abs(checkedValue) / controlValue) * 100L < MEM_DIFFERENCE_PCT;
+ }
+
+ /**
+ * Returns true if difference of checkedValue and controlValue is less than
+ * MEM_DIFFERENCE_PCT percent of controlValue.
+ *
+ * @param checkedValue - checked value
+ * @param controlValue - referent value
+ * @return true if difference of checkedValue and controlValue is less than
+ * MEM_DIFFERENCE_PCT percent of controlValue
+ */
+ private static boolean checkDifferenceRatio(long checkedValue, long controlValue) {
+ return (Math.abs(checkedValue - controlValue) / controlValue) * 100L < MEM_DIFFERENCE_PCT;
+ }
+
+ private static Map<String, Long> getPlabStats(LogParser logParser, LogParser.ReportType type, long gc_id) {
+
+ Map<String, Long> survivorStats = logParser.getEntries()
+ .get(gc_id)
+ .get(type);
+ return survivorStats;
+ }
+
+ /**
+ * Description of one test case.
+ */
+ private static class TestCase {
+
+ private final int wastePct;
+ private final int plabSize;
+ private final int chunkSize;
+ private final int parGCThreads;
+ private final int edenSize;
+ private final boolean plabIsFixed;
+ private final boolean objectsAreReachable;
+ private final boolean promotedByPLAB;
+
+ /**
+ * @param wastePct
+ * ParallelGCBufferWastePct
+ * @param plabSize
+ * -XX:OldPLABSize and -XX:YoungPLABSize
+ * @param chunkSize
+ * requested object size for memory consumption
+ * @param parGCThreads
+ * -XX:ParallelGCThreads
+ * @param edenSize
+ * NewSize and MaxNewSize
+ * @param plabIsFixed
+ * Use dynamic PLAB or fixed size PLAB
+ * @param objectsAreReachable
+ * true - allocate live objects
+ * false - allocate unreachable objects
+ * @param promotedByPLAB
+ * true - we expect to see PLAB allocation during promotion
+ * false - objects will be directly allocated during promotion
+ */
+ public TestCase(int wastePct,
+ int plabSize,
+ int chunkSize,
+ int parGCThreads,
+ int edenSize,
+ boolean plabIsFixed,
+ boolean objectsAreReachable,
+ boolean promotedByPLAB
+ ) {
+ if (wastePct == 0 || plabSize == 0 || chunkSize == 0 || parGCThreads == 0 || edenSize == 0) {
+ throw new IllegalArgumentException("Parameters should not be 0");
+ }
+ this.wastePct = wastePct;
+ this.plabSize = plabSize;
+ this.chunkSize = chunkSize;
+ this.parGCThreads = parGCThreads;
+ this.edenSize = edenSize;
+ this.plabIsFixed = plabIsFixed;
+ this.objectsAreReachable = objectsAreReachable;
+ this.promotedByPLAB = promotedByPLAB;
+ }
+
+ /**
+ * Convert current TestCase to List of options.
+ * Assume test will fill half of existed eden.
+ *
+ * @return
+ * List of options
+ */
+ public List<String> toOptions() {
+ return Arrays.asList("-XX:ParallelGCThreads=" + parGCThreads,
+ "-XX:ParallelGCBufferWastePct=" + wastePct,
+ "-XX:OldPLABSize=" + plabSize,
+ "-XX:YoungPLABSize=" + plabSize,
+ "-XX:" + (plabIsFixed ? "-" : "+") + "ResizePLAB",
+ "-Dchunk.size=" + chunkSize,
+ "-Dreachable=" + objectsAreReachable,
+ "-XX:NewSize=" + edenSize + "m",
+ "-XX:MaxNewSize=" + edenSize + "m",
+ "-Dmem.to.fill=" + getMemToFill()
+ );
+ }
+
+ /**
+ * Print details about test case.
+ */
+ public void print(PrintStream out) {
+ boolean expectPLABAllocation = promotedByPLAB && objectsAreReachable;
+ boolean expectDirectAllocation = (!promotedByPLAB) && objectsAreReachable;
+
+ out.println("Test case details:");
+ out.println(" Young gen size : " + edenSize + "M");
+ out.println(" Predefined PLAB size : " + plabSize);
+ out.println(" Parallel GC buffer waste pct : " + wastePct);
+ out.println(" Chunk size : " + chunkSize);
+ out.println(" Parallel GC threads : " + parGCThreads);
+ out.println(" Objects are created : " + (objectsAreReachable ? "reachable" : "unreachable"));
+ out.println(" PLAB size is fixed: " + (plabIsFixed ? "yes" : "no"));
+ out.println("Test expectations:");
+ out.println(" PLAB allocation : " + (expectPLABAllocation ? "expected" : "unexpected"));
+ out.println(" Direct allocation : " + (expectDirectAllocation ? "expected" : "unexpected"));
+ }
+
+ /**
+ * @return
+ * true if we expect PLAB allocation
+ * false if no
+ */
+ public boolean isPromotedByPLAB() {
+ return promotedByPLAB;
+ }
+
+ /**
+ * @return
+ * true if it is test case for unreachable objects
+ * false for live objects
+ */
+ public boolean isDeadObjectCase() {
+ return !objectsAreReachable;
+ }
+
+ /**
+ * Returns amount of memory to fill
+ *
+ * @return amount of memory
+ */
+ public long getMemToFill() {
+ return (long) (edenSize) * 1024l * 1024l / 2;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/TestPLABResize.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2016, 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 TestPLABResize
+ * @bug 8141278
+ * @summary Test for PLAB resizing
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @requires vm.opt.FlightRecorder != true
+ * @library /testlibrary /../../test/lib /
+ * @modules java.management
+ * @build ClassFileInstaller
+ * sun.hotspot.WhiteBox
+ * gc.g1.plab.lib.LogParser
+ * gc.g1.plab.lib.MemoryConsumer
+ * gc.g1.plab.lib.PLABUtils
+ * gc.g1.plab.lib.AppPLABResize
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main gc.g1.plab.TestPLABResize
+ */
+package gc.g1.plab;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.io.PrintStream;
+
+import gc.g1.plab.lib.LogParser;
+import gc.g1.plab.lib.PLABUtils;
+import gc.g1.plab.lib.AppPLABResize;
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+
+/**
+ * Test for PLAB resizing.
+ */
+public class TestPLABResize {
+
+ private static final int OBJECT_SIZE_SMALL = 10;
+ private static final int OBJECT_SIZE_MEDIUM = 70;
+ private static final int OBJECT_SIZE_HIGH = 150;
+ private static final int GC_NUM_SMALL = 1;
+ private static final int GC_NUM_MEDIUM = 3;
+ private static final int GC_NUM_HIGH = 7;
+ private static final int WASTE_PCT_SMALL = 10;
+ private static final int WASTE_PCT_MEDIUM = 20;
+ private static final int WASTE_PCT_HIGH = 30;
+
+ private static final int ITERATIONS_SMALL = 3;
+ private static final int ITERATIONS_MEDIUM = 5;
+ private static final int ITERATIONS_HIGH = 8;
+
+ private final static TestCase[] TEST_CASES = {
+ new TestCase(WASTE_PCT_SMALL, OBJECT_SIZE_SMALL, GC_NUM_SMALL, ITERATIONS_MEDIUM),
+ new TestCase(WASTE_PCT_SMALL, OBJECT_SIZE_MEDIUM, GC_NUM_HIGH, ITERATIONS_SMALL),
+ new TestCase(WASTE_PCT_SMALL, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, ITERATIONS_HIGH),
+ new TestCase(WASTE_PCT_MEDIUM, OBJECT_SIZE_SMALL, GC_NUM_HIGH, ITERATIONS_MEDIUM),
+ new TestCase(WASTE_PCT_MEDIUM, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, ITERATIONS_SMALL),
+ new TestCase(WASTE_PCT_MEDIUM, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, ITERATIONS_HIGH),
+ new TestCase(WASTE_PCT_HIGH, OBJECT_SIZE_SMALL, GC_NUM_HIGH, ITERATIONS_MEDIUM),
+ new TestCase(WASTE_PCT_HIGH, OBJECT_SIZE_MEDIUM, GC_NUM_SMALL, ITERATIONS_SMALL),
+ new TestCase(WASTE_PCT_HIGH, OBJECT_SIZE_HIGH, GC_NUM_MEDIUM, ITERATIONS_HIGH)
+ };
+
+ public static void main(String[] args) throws Throwable {
+ for (TestCase testCase : TEST_CASES) {
+ testCase.print(System.out);
+ List<String> options = PLABUtils.prepareOptions(testCase.toOptions());
+ options.add(AppPLABResize.class.getName());
+ OutputAnalyzer out = ProcessTools.executeTestJvm(options.toArray(new String[options.size()]));
+ if (out.getExitValue() != 0) {
+ System.out.println(out.getOutput());
+ throw new RuntimeException("Exit code is not 0");
+ }
+ checkResults(out.getOutput(), testCase);
+ }
+ }
+
+ /**
+ * Checks testing results.
+ * Expected results - desired PLAB size is decreased and increased during promotion to Survivor.
+ *
+ * @param output - VM output
+ * @param testCase
+ */
+ private static void checkResults(String output, TestCase testCase) {
+ final LogParser log = new LogParser(output);
+ final Map<Long, Map<LogParser.ReportType, Map<String, Long>>> entries = log.getEntries();
+
+ final ArrayList<Long> plabSizes = entries.entrySet()
+ .stream()
+ .map(item -> {
+ return item.getValue()
+ .get(LogParser.ReportType.SURVIVOR_STATS)
+ .get("desired_plab_sz");
+ })
+ .collect(Collectors.toCollection(ArrayList::new));
+
+ // Check that desired plab size was changed during iterations.
+ // It should decrease during first half of iterations
+ // and increase after.
+ List<Long> decreasedPlabs = plabSizes.subList(testCase.getIterations(), testCase.getIterations() * 2);
+ List<Long> increasedPlabs = plabSizes.subList(testCase.getIterations() * 2, testCase.getIterations() * 3);
+
+ Long prev = decreasedPlabs.get(0);
+ for (int index = 1; index < decreasedPlabs.size(); ++index) {
+ Long current = decreasedPlabs.get(index);
+ if (prev < current) {
+ System.out.println(output);
+ throw new RuntimeException("Test failed! Expect that previous PLAB size should be greater than current. Prev.size: " + prev + " Current size:" + current);
+ }
+ prev = current;
+ }
+
+ prev = increasedPlabs.get(0);
+ for (int index = 1; index < increasedPlabs.size(); ++index) {
+ Long current = increasedPlabs.get(index);
+ if (prev > current) {
+ System.out.println(output);
+ throw new RuntimeException("Test failed! Expect that previous PLAB size should be less than current. Prev.size: " + prev + " Current size:" + current);
+ }
+ prev = current;
+ }
+
+ System.out.println("Test passed!");
+ }
+
+ /**
+ * Description of one test case.
+ */
+ private static class TestCase {
+
+ private final int wastePct;
+ private final int chunkSize;
+ private final int parGCThreads;
+ private final int iterations;
+
+ /**
+ * @param wastePct
+ * ParallelGCBufferWastePct
+ * @param chunkSize
+ * requested object size for memory consumption
+ * @param parGCThreads
+ * -XX:ParallelGCThreads
+ * @param iterations
+ *
+ */
+ public TestCase(int wastePct,
+ int chunkSize,
+ int parGCThreads,
+ int iterations
+ ) {
+ if (wastePct == 0 || chunkSize == 0 || parGCThreads == 0 || iterations == 0) {
+ throw new IllegalArgumentException("Parameters should not be 0");
+ }
+ this.wastePct = wastePct;
+
+ this.chunkSize = chunkSize;
+ this.parGCThreads = parGCThreads;
+ this.iterations = iterations;
+ }
+
+ /**
+ * Convert current TestCase to List of options.
+ *
+ * @return
+ * List of options
+ */
+ public List<String> toOptions() {
+ return Arrays.asList("-XX:ParallelGCThreads=" + parGCThreads,
+ "-XX:ParallelGCBufferWastePct=" + wastePct,
+ "-XX:+ResizePLAB",
+ "-Dthreads=" + parGCThreads,
+ "-Dchunk.size=" + chunkSize,
+ "-Diterations=" + iterations,
+ "-XX:NewSize=16m",
+ "-XX:MaxNewSize=16m"
+ );
+ }
+
+ /**
+ * Print details about test case.
+ */
+ public void print(PrintStream out) {
+ out.println("Test case details:");
+ out.println(" Parallel GC buffer waste pct : " + wastePct);
+ out.println(" Chunk size : " + chunkSize);
+ out.println(" Parallel GC threads : " + parGCThreads);
+ out.println(" Iterations: " + iterations);
+ }
+
+ /**
+ * @return iterations
+ */
+ public int getIterations() {
+ return iterations;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/AppPLABPromotion.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package gc.g1.plab.lib;
+
+import sun.hotspot.WhiteBox;
+
+/**
+ * This application is part of PLAB promotion test.
+ * The application fills a part of young gen with a number of small objects.
+ * Then it calls young GC twice to promote objects from eden to survivor, and from survivor to old.
+ * The test which running the application is responsible to set up test parameters
+ * and VM flags including flags turning GC logging on. The test will then check the produced log.
+ */
+final public class AppPLABPromotion {
+
+ private final static WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+
+ /**
+ * AppPLABPromotion is used for testing PLAB promotion.
+ * Expects the following properties to be set:
+ * - chunk.size - size of one object (byte array)
+ * - mem.to.fill - amount of memory to be consumed
+ * - reachable - memory should be consumed by live or dead objects
+ *
+ * @param args
+ */
+ public static void main(String[] args) {
+ long chunkSize = Long.getLong("chunk.size");
+ long memToFill = Long.getLong("mem.to.fill");
+ boolean reachable = Boolean.getBoolean("reachable");
+ if (chunkSize == 0) {
+ throw new IllegalArgumentException("Chunk size must be not 0");
+ }
+ if (memToFill <= 0) {
+ throw new IllegalArgumentException("mem.to.fill property should be above 0");
+ }
+ // Fill requested amount of memory
+ allocate(reachable, memToFill, chunkSize);
+ // Promote all allocated objects from Eden to Survivor
+ WHITE_BOX.youngGC();
+ // Promote all allocated objects from Survivor to Old
+ WHITE_BOX.youngGC();
+ }
+
+ /**
+ *
+ * @param reachable - should allocate reachable object
+ * @param memSize - Memory to fill
+ * @param chunkSize - requested bytes per objects.
+ * Actual size of bytes per object will be greater
+ */
+ private static void allocate(boolean reachable, long memSize, long chunkSize) {
+ long realSize = WHITE_BOX.getObjectSize(new byte[(int) chunkSize]);
+ int items = (int) ((memSize - 1) / (realSize)) + 1;
+ MemoryConsumer storage;
+ if (reachable) {
+ storage = new MemoryConsumer(items, (int) chunkSize);
+ } else {
+ storage = new MemoryConsumer(1, (int) chunkSize);
+ }
+ // Make all young gen available.
+ WHITE_BOX.fullGC();
+ storage.consume(items * chunkSize);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/AppPLABResize.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package gc.g1.plab.lib;
+
+import jdk.test.lib.Platform;
+import sun.hotspot.WhiteBox;
+
+/**
+ * This application is part of PLAB Resize test.
+ * The application allocates objects in 3 iterations:
+ * 1. Objects of fixed size
+ * 2. Objects of decreasing size
+ * 3. Objects of increasing size
+ * The application doesn't have any assumptions about expected behavior.
+ * It's supposed to be executed by a test which should set up test parameters (object sizes, number of allocations, etc)
+ * and VM flags including flags turning GC logging on. The test will then check the produced log.
+ *
+ * Expects the following properties to be set:
+ * - iterations - amount of iteration per cycle.
+ * - chunk.size - size of objects to be allocated
+ * - threads - number of gc threads (-XX:ParallelGCThreads) to calculate PLAB sizes.
+ */
+final public class AppPLABResize {
+
+ // Memory to be promoted by PLAB for one thread.
+ private static final long MEM_ALLOC_WORDS = 32768;
+ // Defined by properties.
+ private static final int ITERATIONS = Integer.getInteger("iterations");
+ private static final long CHUNK = Long.getLong("chunk.size");
+ private static final int GC_THREADS = Integer.getInteger("threads");
+
+ private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+
+ /**
+ * Main method for AppPLABResizing. Application expect for next properties:
+ * iterations, chunk.size and threads.
+ *
+ * @param args
+ */
+ public static void main(String[] args) {
+
+ if (ITERATIONS == 0 || CHUNK == 0 || GC_THREADS == 0) {
+ throw new IllegalArgumentException("Properties should be set");
+ }
+
+ long wordSize = Platform.is32bit() ? 4l : 8l;
+ // PLAB size is shared between threads.
+ long initialMemorySize = wordSize * GC_THREADS * MEM_ALLOC_WORDS;
+
+ // Expect changing memory to half during all iterations.
+ long memChangeStep = initialMemorySize / 2 / ITERATIONS;
+
+ WHITE_BOX.fullGC();
+
+ // Warm the PLAB. Fill memory ITERATIONS times without changing memory size.
+ iterateAllocation(initialMemorySize, 0);
+ // Fill memory ITERATIONS times.
+ // Initial size is initialMemorySize and step is -memChangeStep
+ iterateAllocation(initialMemorySize, -memChangeStep);
+ // Fill memory ITERATIONS times.
+ // Initial size is memoryAfterChanging, step is memChangeStep.
+ // Memory size at start should be greater then last size on previous step.
+ // Last size on previous step is initialMemorySize - memChangeStep*(ITERATIONS - 1)
+ long memoryAfterChanging = initialMemorySize - memChangeStep * (ITERATIONS - 2);
+ iterateAllocation(memoryAfterChanging, memChangeStep);
+ }
+
+ private static void iterateAllocation(long memoryToFill, long change) {
+ int items;
+ if (change > 0) {
+ items = (int) ((memoryToFill + change * ITERATIONS) / CHUNK) + 1;
+ } else {
+ items = (int) (memoryToFill / CHUNK) + 1;
+ }
+
+ long currentMemToFill = memoryToFill;
+ for (int iteration = 0; iteration < ITERATIONS; ++iteration) {
+ MemoryConsumer storage = new MemoryConsumer(items, (int) CHUNK);
+ storage.consume(currentMemToFill);
+ // Promote all objects to survivor
+ WHITE_BOX.youngGC();
+ storage.clear();
+ currentMemToFill += change;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/LogParser.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package gc.g1.plab.lib;
+
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * LogParser class parses VM output to get PLAB and ConsumptionStats values.
+ *
+ * Typical GC log with PLAB statistics (options - -Xlog:gc=debug,gc+plab=debug) looks like:
+ *
+ * [2,244s][info ][gc ] GC(30) Concurrent Mark abort
+ * [2,245s][debug ][gc,plab] GC(33) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258)
+ * [2,245s][debug ][gc,plab] GC(33) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258)
+ * [2,245s][info ][gc ] GC(33) Pause Young (G1 Evacuation Pause) 127M->127M(128M) (2,244s, 2,245s) 0,899ms
+ * [2,246s][debug ][gc,plab] GC(34) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258)
+ * [2,246s][debug ][gc,plab] GC(34) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258)
+ * [2,246s][info ][gc ] GC(34) Pause Initial Mark (G1 Evacuation Pause) 127M->127M(128M) (2,245s, 2,246s) 0,907ms
+
+ */
+final public class LogParser {
+
+ // Name for GC ID field in report.
+ public final static String GC_ID = "gc_id";
+
+ /**
+ * Type of parsed log element.
+ */
+ public static enum ReportType {
+
+ SURVIVOR_STATS,
+ OLD_STATS
+ }
+
+ private final String log;
+
+ private final Map<Long, Map<ReportType, Map<String,Long>>> reportHolder;
+
+ // GC ID
+ private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)");
+ // Pattern for extraction pair <name>=<numeric value>
+ private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w+\\s+=\\s+\\d+");
+
+ /**
+ * Construct LogParser Object
+ *
+ * @param log - VM Output
+ */
+ public LogParser(String log) {
+ if (log == null) {
+ throw new IllegalArgumentException("Parameter log should not be null.");
+ }
+ this.log = log;
+ reportHolder = parseLines();
+ }
+
+ /**
+ * @return log which is being processed
+ */
+ public String getLog() {
+ return log;
+ }
+
+ /**
+ * Returns list of log entries.
+ *
+ * @return list of Pair with ReportType and Map of parameters/values.
+ */
+ public Map<Long,Map<ReportType, Map<String,Long>>> getEntries() {
+ return reportHolder;
+ }
+
+ private Map<Long,Map<ReportType, Map<String,Long>>> parseLines() throws NumberFormatException {
+ Scanner lineScanner = new Scanner(log);
+ Map<Long,Map<ReportType, Map<String,Long>>> allocationStatistics = new HashMap<>();
+ Optional<Long> gc_id;
+ while (lineScanner.hasNextLine()) {
+ String line = lineScanner.nextLine();
+ gc_id = getGcId(line);
+ if ( gc_id.isPresent() ) {
+ Matcher matcher = PAIRS_PATTERN.matcher(line);
+ if (matcher.find()) {
+ Map<ReportType,Map<String, Long>> oneReportItem;
+ ReportType reportType;
+ // Second line in log is statistics for Old PLAB allocation
+ if ( !allocationStatistics.containsKey(gc_id.get()) ) {
+ oneReportItem = new EnumMap<>(ReportType.class);
+ reportType = ReportType.SURVIVOR_STATS;
+ allocationStatistics.put(gc_id.get(), oneReportItem);
+ } else {
+ oneReportItem = allocationStatistics.get(gc_id.get());
+ reportType = ReportType.OLD_STATS;
+ }
+
+ // Extract all pairs from log.
+ HashMap<String, Long> plabStats = new HashMap<>();
+ do {
+ String pair = matcher.group();
+ String[] nameValue = pair.replaceAll(" ", "").split("=");
+ plabStats.put(nameValue[0], Long.parseLong(nameValue[1]));
+ } while (matcher.find());
+ oneReportItem.put(reportType,plabStats);
+ }
+ }
+ }
+ return allocationStatistics;
+ }
+
+ private Optional<Long> getGcId(String line) {
+ Matcher number = GC_ID_PATTERN.matcher(line);
+ if (number.find()) {
+ return Optional.of(Long.parseLong(number.group(1)));
+ }
+ return Optional.empty();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/MemoryConsumer.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package gc.g1.plab.lib;
+
+/**
+ * The MemoryConsumer is used for consuming different amount of memory.
+ * Class will store not more than 'capacity' number of objects with 'chunk' size.
+ * If we exceed capacity, object will be stored at existing entries,
+ * all previously added objects will be overwritten.
+ * If capacity=1, only last object will be saved.
+ */
+public class MemoryConsumer {
+
+ private int capacity;
+ private int chunk;
+
+ private Object[] array;
+ private int index;
+
+ /**
+ * Create MemoryConsumer object with defined capacity
+ *
+ * @param capacity
+ * @param chunk
+ */
+ public MemoryConsumer(int capacity, int chunk) {
+ if (capacity <= 0) {
+ throw new IllegalArgumentException("Items number should be greater than 0.");
+ }
+ if (chunk <= 0) {
+ throw new IllegalArgumentException("Chunk size should be greater than 0.");
+ }
+ this.capacity = capacity;
+ this.chunk = chunk;
+ index = 0;
+ array = new Object[this.capacity];
+ }
+
+ /**
+ * Store object into MemoryConsumer.
+ *
+ * @param o - Object to store
+ */
+ private void store(Object o) {
+ if (array == null) {
+ throw new RuntimeException("Capacity should be set before storing");
+ }
+ array[index % capacity] = o;
+ ++index;
+ }
+
+ public void consume(long memoryToFill) {
+ long allocated = 0;
+ while (allocated < memoryToFill) {
+ store(new byte[chunk]);
+ allocated += chunk;
+ }
+ }
+
+ /**
+ * Clear all stored objects.
+ */
+ public void clear() {
+ array = null;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/plab/lib/PLABUtils.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package gc.g1.plab.lib;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import jdk.test.lib.Utils;
+
+/**
+ * Utilities for PLAB testing.
+ */
+public class PLABUtils {
+
+ /**
+ * PLAB tests default options list
+ */
+ private final static String[] GC_TUNE_OPTIONS = {
+ "-XX:+UseG1GC",
+ "-XX:G1HeapRegionSize=1m",
+ "-XX:OldSize=64m",
+ "-XX:-UseAdaptiveSizePolicy",
+ "-XX:MaxTenuringThreshold=1",
+ "-XX:-UseTLAB",
+ "-XX:SurvivorRatio=1"
+ };
+
+ /**
+ * GC logging options list.
+ */
+ private final static String G1_PLAB_LOGGING_OPTIONS[] = {
+ "-Xlog:gc=debug,gc+plab=debug"
+ };
+
+ /**
+ * List of options required to use WhiteBox.
+ */
+ private final static String WB_DIAGNOSTIC_OPTIONS[] = {
+ "-Xbootclasspath/a:.",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+WhiteBoxAPI"
+ };
+
+ /**
+ * Prepares options for testing.
+ *
+ * @param options - additional options for testing
+ * @return List of options
+ */
+ public static List<String> prepareOptions(List<String> options) {
+ if (options == null) {
+ throw new IllegalArgumentException("Options cannot be null");
+ }
+ List<String> executionOtions = new ArrayList<>(
+ Arrays.asList(Utils.getTestJavaOpts())
+ );
+ Collections.addAll(executionOtions, WB_DIAGNOSTIC_OPTIONS);
+ Collections.addAll(executionOtions, G1_PLAB_LOGGING_OPTIONS);
+ Collections.addAll(executionOtions, GC_TUNE_OPTIONS);
+ executionOtions.addAll(options);
+ return executionOtions;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/logging/TestDeprecatedPrintFlags.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016, 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 TestDeprecatedPrintFlags
+ * @bug 8145180
+ * @summary Verify PrintGC, PrintGCDetails and -Xloggc
+ * @key gc
+ * @library /testlibrary
+ * @modules java.base/sun.misc
+ * java.management
+ */
+
+import jdk.test.lib.*;
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class TestDeprecatedPrintFlags {
+
+ public static void testPrintGC() throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintGC", "DoGC");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("-XX:+PrintGC is deprecated. Will use -Xlog:gc instead.");
+ output.shouldNotContain("PrintGCDetails");
+ output.stdoutShouldMatch("\\[info.*\\]\\[gc *\\]");
+ output.stdoutShouldNotMatch("\\[info.*\\]\\[gc\\,");
+ output.shouldHaveExitValue(0);
+ }
+
+ public static void testPrintGCDetails() throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintGCDetails", "DoGC");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("-XX:+PrintGCDetails is deprecated. Will use -Xlog:gc* instead.");
+ output.shouldNotContain("PrintGC is deprecated");
+ output.stdoutShouldMatch("\\[info.*\\]\\[gc *\\]");
+ output.stdoutShouldMatch("\\[info.*\\]\\[gc\\,");
+ output.shouldHaveExitValue(0);
+ }
+
+ public static void testXloggc() throws Exception {
+ String fileName = "gc-test.log";
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xloggc:" + fileName, "DoGC");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("-Xloggc is deprecated. Will use -Xlog:gc:gc-test.log instead.");
+ output.shouldNotContain("PrintGCDetails");
+ output.shouldNotContain("PrintGC");
+ output.stdoutShouldNotMatch("\\[info.*\\]\\[gc *\\]");
+ output.stdoutShouldNotMatch("\\[info.*\\]\\[gc\\,");
+ output.shouldHaveExitValue(0);
+ String lines = Files.lines(Paths.get(fileName)).collect(Collectors.joining());
+ System.out.println("lines: " + lines);
+ OutputAnalyzer outputLog = new OutputAnalyzer(lines, "");
+ outputLog.stdoutShouldMatch("\\[info.*\\]\\[gc *\\]");
+ outputLog.stdoutShouldNotMatch("\\[info.*\\]\\[gc\\,");
+ }
+
+ public static void testXloggcWithPrintGCDetails() throws Exception {
+ String fileName = "gc-test.log";
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+PrintGCDetails", "-Xloggc:" + fileName, "DoGC");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("-XX:+PrintGCDetails is deprecated. Will use -Xlog:gc* instead.");
+ output.shouldContain("-Xloggc is deprecated. Will use -Xlog:gc:gc-test.log instead.");
+ output.shouldNotContain("PrintGC is deprecated");
+ output.stdoutShouldNotMatch("\\[info.*\\]\\[gc *\\]");
+ output.stdoutShouldNotMatch("\\[info.*\\]\\[gc\\,");
+ output.shouldHaveExitValue(0);
+ String lines = Files.lines(Paths.get(fileName)).collect(Collectors.joining());
+ OutputAnalyzer outputLog = new OutputAnalyzer(lines, "");
+ outputLog.stdoutShouldMatch("\\[info.*\\]\\[gc *\\]");
+ outputLog.stdoutShouldMatch("\\[info.*\\]\\[gc\\,");
+ }
+
+ public static void main(String[] args) throws Exception {
+ testPrintGC();
+ testPrintGCDetails();
+ testXloggc();
+ testXloggcWithPrintGCDetails();
+ }
+}
+
+class DoGC {
+ public static void main(String[] args) {
+ System.gc();
+ }
+}
--- a/hotspot/test/runtime/Unsafe/AllocateMemory.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/Unsafe/AllocateMemory.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -23,6 +23,7 @@
/*
* @test
+ * @requires vm.compMode != "Xcomp"
* @summary Verifies behaviour of Unsafe.allocateMemory
* @library /testlibrary
* @modules java.base/sun.misc
--- a/hotspot/test/runtime/Unsafe/Reallocate.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/Unsafe/Reallocate.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -23,6 +23,7 @@
/*
* @test
+ * @requires vm.compMode != "Xcomp"
* @bug 8058897
* @library /testlibrary
* @modules java.base/sun.misc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/Class53.jasm Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, 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 8148785
+ * @summary Check that the JVM accepts class files with version 53
+ * @run main Class53
+ */
+
+super public class Class53 version 53:0 {
+
+ public Method "<init>":"()V" stack 1 locals 1 {
+ aload_0;
+ invokespecial Method java/lang/Object."<init>":"()V";
+ return;
+ }
+
+ public static Method main:"([Ljava/lang/String;)V" stack 0 locals 1 {
+ return;
+ }
+
+} // end Class Class53
--- a/hotspot/test/runtime/logging/ClassB.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/logging/ClassB.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
--- a/hotspot/test/runtime/logging/ClassInitializationTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/logging/ClassInitializationTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -40,7 +40,10 @@
public static void main(String... args) throws Exception {
// (1)
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:classinit=info", "-Xverify:all", "-Xmx64m", "BadMap50");
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:classinit=info",
+ "-Xverify:all",
+ "-Xmx64m",
+ "BadMap50");
OutputAnalyzer out = new OutputAnalyzer(pb.start());
out.shouldContain("Start class verification for:");
out.shouldContain("End class verification for:");
@@ -50,16 +53,29 @@
// (2)
if (Platform.isDebugBuild()) {
- pb = ProcessTools.createJavaProcessBuilder("-Xlog:classinit=info", "-Xverify:all", "-XX:+EagerInitialization", "-Xmx64m", "-version");
- out = new OutputAnalyzer(pb.start());
- out.shouldContain("[Initialized").shouldContain("without side effects]");
- out.shouldHaveExitValue(0);
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog:classinit=info",
+ "-Xverify:all",
+ "-XX:+EagerInitialization",
+ "-Xmx64m",
+ InnerClass.class.getName());
+ out = new OutputAnalyzer(pb.start());
+ out.shouldContain("[Initialized").shouldContain("without side effects]");
+ out.shouldHaveExitValue(0);
}
// (3) Ensure that VerboseVerification still triggers appropriate messages.
- pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions", "-XX:+VerboseVerification", "-Xverify:all", "-Xmx64m", "BadMap50");
+ pb = ProcessTools.createJavaProcessBuilder("-XX:+UnlockDiagnosticVMOptions",
+ "-XX:+VerboseVerification",
+ "-Xverify:all",
+ "-Xmx64m",
+ "BadMap50");
out = new OutputAnalyzer(pb.start());
out.shouldContain("End class verification for:");
out.shouldContain("Verification for BadMap50 failed");
out.shouldContain("Fail over class verification to old verifier for: BadMap50");
}
+ public static class InnerClass {
+ public static void main(String[] args) throws Exception {
+ System.out.println("Inner Class");
+ }
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/ClassLoadUnloadTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2016, 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 ClassLoadUnloadTest
+ * @bug 8142506
+ * @library /testlibrary /runtime/testlibrary
+ * @library classes
+ * @build ClassUnloadCommon test.Empty jdk.test.lib.* jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools
+ * @run driver ClassLoadUnloadTest
+ */
+
+import jdk.test.lib.*;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ClassLoadUnloadTest {
+ private static OutputAnalyzer out;
+ private static ProcessBuilder pb;
+ private static class ClassUnloadTestMain {
+ public static void main(String... args) throws Exception {
+ String className = "test.Empty";
+ ClassLoader cl = ClassUnloadCommon.newClassLoader();
+ Class<?> c = cl.loadClass(className);
+ cl = null; c = null;
+ ClassUnloadCommon.triggerUnloading();
+ }
+ }
+
+ static void checkFor(String... outputStrings) throws Exception {
+ out = new OutputAnalyzer(pb.start());
+ for (String s: outputStrings) {
+ out.shouldContain(s);
+ }
+ out.shouldHaveExitValue(0);
+ }
+
+ static void checkAbsent(String... outputStrings) throws Exception {
+ out = new OutputAnalyzer(pb.start());
+ for (String s: outputStrings) {
+ out.shouldNotContain(s);
+ }
+ out.shouldHaveExitValue(0);
+ }
+
+ // Use the same command-line heap size setting as ../ClassUnload/UnloadTest.java
+ static ProcessBuilder exec(String... args) throws Exception {
+ List<String> argsList = new ArrayList<>();
+ Collections.addAll(argsList, args);
+ Collections.addAll(argsList, "-Xmn8m");
+ Collections.addAll(argsList, "-Dtest.classes=" + System.getProperty("test.classes","."));
+ Collections.addAll(argsList, ClassUnloadTestMain.class.getName());
+ return ProcessTools.createJavaProcessBuilder(argsList.toArray(new String[argsList.size()]));
+ }
+
+ public static void main(String... args) throws Exception {
+
+ // -Xlog:classunload=info
+ pb = exec("-Xlog:classunload=info");
+ checkFor("[classunload]", "unloading class");
+
+ // -Xlog:classunload=off
+ pb = exec("-Xlog:classunload=off");
+ checkAbsent("[classunload]");
+
+ // -XX:+TraceClassUnloading
+ pb = exec("-XX:+TraceClassUnloading");
+ checkFor("[classunload]", "unloading class");
+
+ // -XX:-TraceClassUnloading
+ pb = exec("-XX:-TraceClassUnloading");
+ checkAbsent("[classunload]");
+
+ // -Xlog:classload=info
+ pb = exec("-Xlog:classload=info");
+ checkFor("[classload]", "java.lang.Object", "source:");
+
+ // -Xlog:classload=debug
+ pb = exec("-Xlog:classload=debug");
+ checkFor("[classload]", "java.lang.Object", "source:", "klass:", "super:", "loader:", "bytes:");
+
+ // -Xlog:classload=off
+ pb = exec("-Xlog:classload=off");
+ checkAbsent("[classload]");
+
+ // -XX:+TraceClassLoading
+ pb = exec("-XX:+TraceClassLoading");
+ checkFor("[classload]", "java.lang.Object", "source:");
+
+ // -XX:-TraceClassLoading
+ pb = exec("-XX:-TraceClassLoading");
+ checkAbsent("[classload]");
+
+ // -verbose:class
+ pb = exec("-verbose:class");
+ checkFor("[classload]", "java.lang.Object", "source:");
+ checkFor("[classunload]", "unloading class");
+
+ // -Xlog:classloaderdata=trace
+ pb = exec("-Xlog:classloaderdata=trace");
+ checkFor("[classloaderdata]", "create class loader data");
+
+ }
+}
--- a/hotspot/test/runtime/logging/ClassResolutionTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/logging/ClassResolutionTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -58,26 +58,28 @@
public static void main(String... args) throws Exception {
// (1) classresolve should turn on.
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:classresolve=info", ClassResolutionTestMain.class.getName());
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:classresolve=info",
+ ClassResolutionTestMain.class.getName());
OutputAnalyzer o = new OutputAnalyzer(pb.start());
o.shouldContain("[classresolve] ClassResolutionTest$ClassResolutionTestMain$Thing1Handler ClassResolutionTest$ClassResolutionTestMain$Thing1");
// (2) classresolve should turn off.
- pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog", "-Xlog:classresolve=off", ClassResolutionTestMain.class.getName());
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog",
+ "-Xlog:classresolve=off",
+ ClassResolutionTestMain.class.getName());
o = new OutputAnalyzer(pb.start());
o.shouldNotContain("[classresolve]");
// (3) TraceClassResolution should turn on.
- pb = ProcessTools.createJavaProcessBuilder(
- "-XX:+TraceClassResolution", ClassResolutionTestMain.class.getName());
+ pb = ProcessTools.createJavaProcessBuilder("-XX:+TraceClassResolution",
+ ClassResolutionTestMain.class.getName());
o = new OutputAnalyzer(pb.start());
o.shouldContain("[classresolve] ClassResolutionTest$ClassResolutionTestMain$Thing1Handler ClassResolutionTest$ClassResolutionTestMain$Thing1");
// (4) TraceClassResolution should turn off.
- pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog", "-XX:-TraceClassResolution", ClassResolutionTestMain.class.getName());
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog",
+ "-XX:-TraceClassResolution",
+ ClassResolutionTestMain.class.getName());
o = new OutputAnalyzer(pb.start());
o.shouldNotContain("[classresolve]");
--- a/hotspot/test/runtime/logging/DefaultMethodsTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/logging/DefaultMethodsTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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,7 +26,6 @@
* @bug 8139564
* @summary defaultmethods=debug should have logging from each of the statements in the code
* @library /testlibrary
- * @ignore 8146435
* @modules java.base/sun.misc
* java.management
* @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools
@@ -38,8 +37,8 @@
public class DefaultMethodsTest {
public static void main(String[] args) throws Exception {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:defaultmethods=debug", "-version");
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:defaultmethods=debug",
+ InnerClass.class.getName());
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("Slots that need filling:");
output.shouldContain("requires default method processing");
@@ -51,5 +50,11 @@
output.shouldContain("default methods");
output.shouldHaveExitValue(0);
}
+
+ public static class InnerClass {
+ public static void main(String[] args) throws Exception {
+ System.out.println("Inner Class");
+ }
+ }
}
--- a/hotspot/test/runtime/logging/ExceptionsTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/logging/ExceptionsTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -23,8 +23,8 @@
/*
* @test
- * @bug 8141211
- * @summary exceptions=info output should have an exception message for both interpreter and compiled methods
+ * @bug 8141211 8147477
+ * @summary exceptions=info output should have an exception message for interpreter methods
* @library /testlibrary
* @modules java.base/sun.misc
* java.management
@@ -32,16 +32,21 @@
* @run driver ExceptionsTest
*/
+import java.io.File;
+import java.util.Map;
import jdk.test.lib.OutputAnalyzer;
import jdk.test.lib.ProcessTools;
public class ExceptionsTest {
+ static void updateEnvironment(ProcessBuilder pb, String environmentVariable, String value) {
+ Map<String, String> env = pb.environment();
+ env.put(environmentVariable, value);
+ }
+
static void analyzeOutputOn(ProcessBuilder pb) throws Exception {
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("<a 'java/lang/RuntimeException': Test exception 1 for logging>");
output.shouldContain(" thrown in interpreter method ");
- output.shouldContain(" thrown in compiled method ");
- output.shouldContain("Exception 2 caught.");
output.shouldHaveExitValue(0);
}
@@ -52,47 +57,43 @@
}
public static void main(String[] args) throws Exception {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:exceptions=info", "-Xcomp",
- "-XX:CompileCommand=compileonly,ExceptionsTest$InternalClass::compileMe",
- InternalClass.class.getName());
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:exceptions=info",
+ InternalClass.class.getName());
analyzeOutputOn(pb);
- pb = ProcessTools.createJavaProcessBuilder(
- "-XX:+TraceExceptions", "-Xcomp",
- "-XX:CompileCommand=compileonly,ExceptionsTest$InternalClass::compileMe",
- InternalClass.class.getName());
+ pb = ProcessTools.createJavaProcessBuilder("-XX:+TraceExceptions",
+ InternalClass.class.getName());
analyzeOutputOn(pb);
- pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:exceptions=off", "-Xcomp",
- "-XX:CompileCommand=compileonly,ExceptionsTest$InternalClass::compileMe",
- InternalClass.class.getName());
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog:exceptions=off",
+ InternalClass.class.getName());
+ analyzeOutputOff(pb);
+
+ pb = ProcessTools.createJavaProcessBuilder("-XX:-TraceExceptions",
+ InternalClass.class.getName());
analyzeOutputOff(pb);
- pb = ProcessTools.createJavaProcessBuilder(
- "-XX:-TraceExceptions", "-Xcomp",
- "-XX:CompileCommand=compileonly,ExceptionsTest$InternalClass::compileMe",
- InternalClass.class.getName());
+ pb = ProcessTools.createJavaProcessBuilder(InternalClass.class.getName());
+ updateEnvironment(pb, "_JAVA_OPTIONS", "-XX:+TraceExceptions");
+ analyzeOutputOn(pb);
+
+ pb = ProcessTools.createJavaProcessBuilder(InternalClass.class.getName());
+ updateEnvironment(pb, "JAVA_TOOL_OPTIONS", "-Xlog:exceptions=info -XX:-TraceExceptions");
analyzeOutputOff(pb);
+
+ pb = ProcessTools.createJavaProcessBuilder("-XX:VMOptionsFile=" + System.getProperty("test.src", ".")
+ + File.separator + "ExceptionsTest_options_file",
+ InternalClass.class.getName());
+ analyzeOutputOn(pb);
}
public static class InternalClass {
- public static void compileMe() throws Exception {
- try {
- throw new RuntimeException("Test exception 2 for logging");
- } catch (Exception e) {
- System.out.println("Exception 2 caught.");
- }
- }
-
public static void main(String[] args) throws Exception {
try {
throw new RuntimeException("Test exception 1 for logging");
} catch (Exception e) {
System.out.println("Exception 1 caught.");
}
- compileMe();
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/ExceptionsTest_options_file Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,1 @@
+-XX:+TraceExceptions
--- a/hotspot/test/runtime/logging/ItablesTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/logging/ItablesTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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,8 +27,8 @@
* @summary itables=trace should have logging from each of the statements
* in the code
* @library /testlibrary
- * @ignore 8146435
* @compile ClassB.java
+ * ItablesVtableTest.java
* @modules java.base/sun.misc
* java.management
* @run driver ItablesTest
@@ -39,12 +39,10 @@
public class ItablesTest {
public static void main(String[] args) throws Exception {
if (Platform.isDebugBuild()) {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:itables=trace", "ClassB");
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:itables=trace", "ClassB");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain(": Initializing itables for ClassB");
output.shouldContain(": Initializing itable indices for interface ");
- output.shouldContain("vtable index ");
output.shouldContain("itable index ");
output.shouldContain("target: ClassB.Method1()V, method_holder: ClassB target_method flags: public");
output.shouldContain("invokeinterface resolved method: caller-class");
@@ -53,6 +51,11 @@
output.shouldContain("invokeinterface selected method: receiver-class");
output.shouldContain("Resolving: klass: ");
output.shouldHaveExitValue(0);
+
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog:itables=trace", "ItablesVtableTest");
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("vtable index ");
+ output.shouldHaveExitValue(0);
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/ItablesVtableTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+interface Interface1 {
+ public void foo();
+ public int hashCode();
+}
+
+public class ItablesVtableTest implements Interface1 {
+ public void foo() {
+ System.out.println("ItablesVtableTest foo");
+ }
+ public int hashCode() {
+ return 55;
+ }
+
+ public static void main(String[] unused) {
+ ItablesVtableTest c = new ItablesVtableTest();
+ c.foo();
+ System.out.println("Interface1 hashCode " + c.hashCode());
+ }
+}
--- a/hotspot/test/runtime/logging/MonitorInflationTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/logging/MonitorInflationTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -51,20 +51,20 @@
}
public static void main(String[] args) throws Exception {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:monitorinflation=debug", InnerClass.class.getName());
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:monitorinflation=debug",
+ InnerClass.class.getName());
analyzeOutputOn(pb);
- pb = ProcessTools.createJavaProcessBuilder(
- "-XX:+TraceMonitorInflation", InnerClass.class.getName());
+ pb = ProcessTools.createJavaProcessBuilder("-XX:+TraceMonitorInflation",
+ InnerClass.class.getName());
analyzeOutputOn(pb);
- pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:monitorinflation=off", InnerClass.class.getName());
+ pb = ProcessTools.createJavaProcessBuilder("-Xlog:monitorinflation=off",
+ InnerClass.class.getName());
analyzeOutputOff(pb);
- pb = ProcessTools.createJavaProcessBuilder(
- "-XX:-TraceMonitorInflation", InnerClass.class.getName());
+ pb = ProcessTools.createJavaProcessBuilder("-XX:-TraceMonitorInflation",
+ InnerClass.class.getName());
analyzeOutputOff(pb);
}
--- a/hotspot/test/runtime/logging/SafepointTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/logging/SafepointTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -38,8 +38,8 @@
public class SafepointTest {
public static void main(String[] args) throws Exception {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:safepoint=trace", InnerClass.class.getName());
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:safepoint=trace",
+ InnerClass.class.getName());
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("Safepoint synchronization initiated. (");
output.shouldContain("Entering safepoint region: ");
--- a/hotspot/test/runtime/logging/VMOperationTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/logging/VMOperationTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -38,9 +38,10 @@
public class VMOperationTest {
public static void main(String[] args) throws Exception {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:vmoperation=debug", "-Xmx64m", "-Xms64m",
- InternalClass.class.getName());
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:vmoperation=debug",
+ "-Xmx64m",
+ "-Xms64m",
+ InternalClass.class.getName());
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("VM_Operation (");
output.shouldHaveExitValue(0);
--- a/hotspot/test/runtime/logging/VtablesTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/logging/VtablesTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -41,8 +41,7 @@
public class VtablesTest {
public static void main(String[] args) throws Exception {
if (Platform.isDebugBuild()) {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-Xlog:vtables=trace", "ClassB");
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:vtables=trace", "ClassB");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldContain("copy vtable from ClassA to ClassB");
output.shouldContain("Initializing: ClassB");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/logging/classes/test/Empty.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,5 @@
+package test;
+
+public class Empty {
+public String toString() { return "nothing"; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/os/AvailableProcessors.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.File;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.OutputAnalyzer;
+import java.util.ArrayList;
+
+/*
+ * @test
+ * @bug 6515172 8148766
+ * @summary Check that availableProcessors reports the correct value when running in a cpuset on linux
+ * @requires os.family == "linux"
+ * @library /testlibrary
+ * @build jdk.test.lib.*
+ * @run driver AvailableProcessors
+ */
+public class AvailableProcessors {
+
+ static final String SUCCESS_STRING = "Found expected processors: ";
+
+ public static void main(String[] args) throws Exception {
+ if (args.length > 0)
+ checkProcessors(Integer.parseInt(args[0]));
+ else {
+ // run ourselves under different cpu configurations
+ // using the taskset command
+ String taskset;
+ final String taskset1 = "/bin/taskset";
+ final String taskset2 = "/usr/bin/taskset";
+ if (new File(taskset1).exists())
+ taskset = taskset1;
+ else if (new File(taskset2).exists())
+ taskset = taskset2;
+ else {
+ System.out.println("Skipping test: could not find taskset command");
+ return;
+ }
+
+ int available = Runtime.getRuntime().availableProcessors();
+
+ if (available == 1) {
+ System.out.println("Skipping test: only one processor available");
+ return;
+ }
+
+ // Get the java command we want to execute
+ // Enable logging for easier failure diagnosis
+ ProcessBuilder master =
+ ProcessTools.createJavaProcessBuilder(false,
+ "-Xlog:os=trace",
+ "AvailableProcessors");
+
+ int[] expected = new int[] { 1, available/2, available-1, available };
+
+ for (int i : expected) {
+ System.out.println("Testing for " + i + " processors ...");
+ int max = i - 1;
+ ArrayList<String> cmdline = new ArrayList<>(master.command());
+ // prepend taskset command
+ cmdline.add(0, "0-" + max);
+ cmdline.add(0, "-c");
+ cmdline.add(0, taskset);
+ // append expected processor count
+ cmdline.add(String.valueOf(i));
+ ProcessBuilder pb = new ProcessBuilder(cmdline);
+ System.out.println("Final command line: " +
+ ProcessTools.getCommandLine(pb));
+ OutputAnalyzer output = ProcessTools.executeProcess(pb);
+ output.shouldContain(SUCCESS_STRING);
+ }
+ }
+ }
+
+ static void checkProcessors(int expected) {
+ int available = Runtime.getRuntime().availableProcessors();
+ // available can dynamically drop below expected due to aggressive power management
+ // but we should never have more than expected, else taskset is broken
+ if (available <= 0 || available > expected)
+ throw new Error("Expected " + expected + " processors, but found "
+ + available);
+ else
+ System.out.println(SUCCESS_STRING + available);
+ }
+}
--- a/hotspot/test/runtime/testlibrary/ClassUnloadCommon.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/runtime/testlibrary/ClassUnloadCommon.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, 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,6 +21,12 @@
* questions.
*/
+
+/*
+ * To use ClassUnloadCommon from a sub-process, see hotspot/test/runtime/logging/ClassLoadUnloadTest.java
+ * for an example.
+ */
+
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
--- a/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpAllTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -33,7 +33,7 @@
* @build jdk.test.lib.*
* @build jdk.test.lib.dcmd.*
* @build jdk.test.lib.hprof.*
- * @build jdk.test.lib.hprof.module.*
+ * @build jdk.test.lib.hprof.model.*
* @build jdk.test.lib.hprof.parser.*
* @build jdk.test.lib.hprof.utils.*
* @build HeapDumpTest
--- a/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/serviceability/dcmd/gc/HeapDumpTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -49,7 +49,7 @@
* @build jdk.test.lib.*
* @build jdk.test.lib.dcmd.*
* @build jdk.test.lib.hprof.*
- * @build jdk.test.lib.hprof.module.*
+ * @build jdk.test.lib.hprof.model.*
* @build jdk.test.lib.hprof.parser.*
* @build jdk.test.lib.hprof.utils.*
* @run testng HeapDumpTest
--- a/hotspot/test/serviceability/tmtools/jstack/WaitNotifyThreadTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/serviceability/tmtools/jstack/WaitNotifyThreadTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -88,6 +88,7 @@
}
private void doTest() throws Exception {
+
// Verify stack trace consistency when notifying the thread
doTest(new ActionNotify());
@@ -134,8 +135,7 @@
if (mi.getName().startsWith(OBJECT_WAIT) && mi.getCompilationUnit() == null /*native method*/) {
if (mi.getLocks().size() == 1) {
MonitorInfo monInfo = mi.getLocks().getFirst();
- if (monInfo.getType().equals("waiting on")
- && monInfo.getMonitorClass().equals(OBJECT)) {
+ if (monInfo.getType().equals("waiting on") && compareMonitorClass(monInfo)) {
monitorAddress = monInfo.getMonitorAddress();
} else {
System.err.println("Error: incorrect monitor info: " + monInfo.getType() + ", " + monInfo.getMonitorClass());
@@ -166,7 +166,7 @@
private void assertMonitorInfo(String expectedMessage, MonitorInfo monInfo, String monitorAddress) {
if (monInfo.getType().equals(expectedMessage)
- && monInfo.getMonitorClass().equals(OBJECT + "11")
+ && compareMonitorClass(monInfo)
&& monInfo.getMonitorAddress().equals(
monitorAddress)) {
System.out.println("Correct monitor info found");
@@ -177,6 +177,13 @@
}
}
+ private boolean compareMonitorClass(MonitorInfo monInfo) {
+ // If monitor class info is present in the jstack output
+ // then compare it with the class of the actual monitor object
+ // If there is no monitor class info available then return true
+ return OBJECT.equals(monInfo.getMonitorClass()) || (monInfo.getMonitorClass() == null);
+ }
+
private void analyzeThreadStackNoWaiting(ThreadStack ti2) {
Iterator<MethodInfo> it = ti2.getStack().iterator();
--- a/hotspot/test/serviceability/tmtools/jstack/utils/DefaultFormat.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/serviceability/tmtools/jstack/utils/DefaultFormat.java Wed Jul 05 21:21:58 2017 +0200
@@ -70,10 +70,18 @@
return "^JNI\\sglobal\\sreferences:\\s((.+))$";
}
+ // Sample string that matches the pattern:
+ // waiting on <0x000000008f64e6d0> (a java.lang.Object)
protected String monitorInfoPattern() {
return "^\\s+\\-\\s(locked|waiting\\son|waiting\\sto\\slock)\\s\\<(.*)\\>\\s\\(((.*))\\)$";
}
+ // Sample string that matches the pattern:
+ // waiting on <no object reference available>
+ protected String monitorInfoNoObjectRefPattern() {
+ return "^\\s+\\-\\s(locked|waiting\\son|waiting\\sto\\slock)\\s\\<(.*)\\>$";
+ }
+
protected String vmVersionInfoPattern() {
return "Full\\sthread\\sdump\\s.*";
}
@@ -100,7 +108,10 @@
currentMethodInfo = parseMethodInfo(line);
currentThreadStack.addMethod(currentMethodInfo);
} else if (line.matches(monitorInfoPattern())) {
- MonitorInfo mi = parseMonitorInfo(line);
+ MonitorInfo mi = parseMonitorInfo(line, monitorInfoPattern());
+ currentMethodInfo.getLocks().add(mi);
+ } else if (line.matches(monitorInfoNoObjectRefPattern())) {
+ MonitorInfo mi = parseMonitorInfo(line, monitorInfoNoObjectRefPattern());
currentMethodInfo.getLocks().add(mi);
} else if (line.matches(extendedStatusPattern())) {
currentThreadStack.setExtendedStatus(parseExtendedStatus(line));
@@ -125,16 +136,17 @@
return result;
}
- private MonitorInfo parseMonitorInfo(String line) {
+ private MonitorInfo parseMonitorInfo(String line, String pattern) {
Scanner s = new Scanner(line);
- s.findInLine(monitorInfoPattern());
+ s.findInLine(pattern);
MonitorInfo mi = new MonitorInfo();
MatchResult res = s.match();
mi.setType(res.group(1));
mi.setMonitorAddress(res.group(2));
- mi.setMonitorClass(res.group(3));
-
+ if (res.groupCount() > 2) {
+ mi.setMonitorClass(res.group(3));
+ }
return mi;
}
--- a/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/serviceability/tmtools/jstat/GcCapacityTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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,7 +29,7 @@
* displayed with jstat -gccapacity.
* @library /test/lib/share/classes
* @library ../share
- * @ignore 8147848
+ * @requires vm.opt.ExplicitGCInvokesConcurrent != true
* @build common.*
* @build utils.*
* @run main/othervm -XX:+UsePerfData GcCapacityTest
--- a/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/serviceability/tmtools/jstat/GcCauseTest01.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -30,7 +30,7 @@
* collection time increase.
* @library /test/lib/share/classes
* @library ../share
- * @ignore 8147848
+ * @requires vm.opt.ExplicitGCInvokesConcurrent != true
* @build common.*
* @build utils.*
*
--- a/hotspot/test/serviceability/tmtools/jstat/GcTest01.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/serviceability/tmtools/jstat/GcTest01.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -33,7 +33,7 @@
* collection time increase.
* @library /test/lib/share/classes
* @library ../share
- * @ignore 8147848
+ * @requires vm.opt.ExplicitGCInvokesConcurrent != true
* @build common.*
* @build utils.*
*
--- a/hotspot/test/serviceability/tmtools/jstat/utils/GcProvokerImpl.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/GcProvokerImpl.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -61,7 +61,7 @@
long edenSize = Pools.getEdenCommittedSize();
long heapSize = Pools.getHeapCommittedSize();
float targetPercent = ((float) edenSize) / (heapSize);
- if ((targetPercent <= 0) || (targetPercent > 1.0)) {
+ if ((targetPercent < 0) || (targetPercent > 1.0)) {
throw new RuntimeException("Error in the percent calculation" + " (eden size: " + edenSize + ", heap size: " + heapSize + ", calculated eden percent: " + targetPercent + ")");
}
eatHeapMemory(targetPercent);
--- a/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCapacityResults.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/serviceability/tmtools/jstat/utils/JstatGcCapacityResults.java Wed Jul 05 21:21:58 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, 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
@@ -77,10 +77,10 @@
assertThat(NGC <= NGCMX, "NGC > NGCMX (generation capacity > max generation capacity)");
float S0C = getFloatValue("S0C");
- assertThat(S0C < NGC, "S0C >= NGC (survivor space 0 capacity >= new generation capacity)");
+ assertThat(S0C <= NGC, "S0C > NGC (survivor space 0 capacity > new generation capacity)");
float S1C = getFloatValue("S1C");
- assertThat(S1C < NGC, "S1C >= NGC (survivor space 1 capacity >= new generation capacity)");
+ assertThat(S1C <= NGC, "S1C > NGC (survivor space 1 capacity > new generation capacity)");
float EC = getFloatValue("EC");
assertThat(EC <= NGC, "EC > NGC (eden space capacity > new generation capacity)");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/stress/gc/TestStressRSetCoarsening.java Wed Jul 05 21:21:58 2017 +0200
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.concurrent.TimeoutException;
+import sun.hotspot.WhiteBox;
+
+/*
+ * @test TestStressRSetCoarsening.java
+ * @key stress
+ * @bug 8146984 8147087
+ * @requires vm.gc=="G1" | vm.gc=="null"
+ * @requires os.maxMemory > 3G
+ *
+ * @summary Stress G1 Remembered Set by creating a lot of cross region links
+ * @modules java.base/sun.misc
+ * @library /testlibrary /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm/timeout=300
+ * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 1 0 300
+ * @run main/othervm/timeout=300
+ * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ * -Xmx500m -XX:G1HeapRegionSize=8m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 1 10 300
+ * @run main/othervm/timeout=300
+ * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ * -Xmx500m -XX:G1HeapRegionSize=32m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 42 10 300
+ * @run main/othervm/timeout=300
+ * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ * -Xmx500m -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 2 0 300
+ * @run main/othervm/timeout=1800
+ * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ * -Xmx1G -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 500 0 1800
+ * @run main/othervm/timeout=1800
+ * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:+UseG1GC
+ * -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGC -XX:+PrintGCTimeStamps -Xlog:gc
+ * -Xmx1G -XX:G1HeapRegionSize=1m -XX:MaxGCPauseMillis=1000 TestStressRSetCoarsening 10 10 1800
+ */
+
+/**
+ * What the test does.
+ * Preparation stage:
+ * Fill out ~90% of the heap with objects, each object is an object array.
+ * If we want to allocate K objects per region, we calculate N to meet:
+ * sizeOf(Object[N]) ~= regionSize / K
+ * Stress stage:
+ * No more allocation, so no more GC.
+ * We will perform a number of iterations. On each iteration i,
+ * for each pair of regions Rx and Ry we will set c[i] references
+ * from Rx to Ry. If c[i] less than c[i-1] at the end of iteration
+ * concurrent mark cycle will be initiated (to recalculate remembered sets).
+ * As the result RSet will be growing up and down, up and down many times.
+ *
+ * The test expects: no crash and no timeouts.
+ *
+ * Test Parameters:
+ * args[0] - number of objects per Heap Region (1 - means humongous)
+ * args[1] - number of regions to refresh to provoke GC at the end of cycle.
+ * (0 - means no GC, i.e. no reading from RSet)
+ * args[2] - timeout in seconds (to stop execution to avoid jtreg timeout)
+ */
+public class TestStressRSetCoarsening {
+
+ public static void main(String... args) throws InterruptedException {
+ if (args.length != 3) {
+ throw new IllegalArgumentException("Wrong number of arguments " + args.length);
+ }
+ int objectsPerRegion = Integer.parseInt(args[0]); // 1 means humongous
+ int regsToRefresh = Integer.parseInt(args[1]); // 0 means no regions to refresh at the end of cycle
+ int timeout = Integer.parseInt(args[2]); // in seconds, test should stop working eariler
+ new TestStressRSetCoarsening(objectsPerRegion, regsToRefresh, timeout).go();
+ }
+
+ private static final long KB = 1024;
+ private static final long MB = 1024 * KB;
+
+ private static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+ public final Object[][] storage;
+
+ /**
+ * Number of objects per region. This is a test parameter.
+ */
+ public final int K;
+
+ /**
+ * Length of object array: sizeOf(Object[N]) ~= regionSize / K
+ * N will be calculated as function of K.
+ */
+ public final int N;
+
+ /**
+ * How many regions involved into testing.
+ * Will be calculated as heapFractionToAllocate * freeRegionCount.
+ */
+ public final int regionCount;
+
+ /**
+ * How much heap to use.
+ */
+ public final float heapFractionToAllocate = 0.9f;
+
+ /**
+ * How many regions to be refreshed at the end of cycle.
+ * This is a test parameter.
+ */
+ public final int regsToRefresh;
+
+ /**
+ * Initial time.
+ */
+ public final long start;
+
+ /**
+ * Time when the test should stop working.
+ */
+ public final long finishAt;
+
+ /**
+ * Does pre-calculation and allocate necessary objects.
+ *
+ * @param objPerRegions how many objects per G1 heap region
+ */
+ TestStressRSetCoarsening(int objPerRegions, int regsToRefresh, int timeout) {
+ this.K = objPerRegions;
+ this.regsToRefresh = regsToRefresh;
+ this.start = System.currentTimeMillis();
+ this.finishAt = start + timeout * 900; // 10% ahead of jtreg timeout
+
+ long regionSize = WB.g1RegionSize();
+
+ // How many free regions
+ Runtime rt = Runtime.getRuntime();
+ long used = rt.totalMemory() - rt.freeMemory();
+ long totalFree = rt.maxMemory() - used;
+ regionCount = (int) ((totalFree / regionSize) * heapFractionToAllocate);
+ long toAllocate = regionCount * regionSize;
+ System.out.println("%% Test parameters");
+ System.out.println("%% Objects per region : " + K);
+ System.out.println("%% Heap fraction to allocate : " + (int) (heapFractionToAllocate * 100) + "%");
+ System.out.println("%% Regions to refresh to provoke GC: " + regsToRefresh);
+
+ System.out.println("%% Memory");
+ System.out.println("%% used : " + used / MB + "M");
+ System.out.println("%% available : " + totalFree / MB + "M");
+ System.out.println("%% to allocate : " + toAllocate / MB + "M");
+ System.out.println("%% (in regs) : " + regionCount);
+ System.out.println("%% G1 Region Size: " + regionSize / MB + "M");
+
+ int refSize = WB.getHeapOopSize();
+
+ // Calculate N: K*sizeOf(Object[N]) ~= regionSize
+ // sizeOf(Object[N]) ~= (N+4)*refSize
+ // ==>
+ // N = regionSize / K / refSize - 4;
+ N = (int) ((regionSize / K) / refSize) - 5;
+
+ /*
+ * --------------
+ * region0 storage[0] = new Object[N]
+ * ...
+ * storage[K-1] = new Object[N]
+ * ---------------
+ * region1 storage[K] = new Object[N]
+ * ...
+ * storage[2*K - 1] = new Object[N]
+ * --------------
+ * ...
+ * --------------
+ * regionX storage[X*K] = new Object[N]
+ * ...
+ * storage[(X+1)*K -1] = new Object[N]
+ * where X = HeapFraction * TotalRegions
+ * -------------
+ */
+ System.out.println("%% Objects");
+ System.out.println("%% N (array length) : " + N);
+ System.out.println("%% K (objects in regions): " + K);
+ System.out.println("%% Reference size : " + refSize);
+ System.out.println("%% Approximate obj size : " + (N + 2) * refSize / KB + "K)");
+
+ storage = new Object[regionCount * K][];
+ for (int i = 0; i < storage.length; i++) {
+ storage[i] = new Object[N];
+ }
+ }
+
+ public void go() throws InterruptedException {
+ // threshold for sparce -> fine
+ final int FINE = WB.getIntxVMFlag("G1RSetSparseRegionEntries").intValue();
+
+ // threshold for fine -> coarse
+ final int COARSE = WB.getIntxVMFlag("G1RSetRegionEntries").intValue();
+
+ // regToRegRefCounts - array of reference counts from region to region
+ // at the the end of iteration.
+ // The number of test iterations is array length - 1.
+ // If c[i] > c[i-1] then during the iteration i more references will
+ // be created.
+ // If c[i] < c[i-1] then some referenes will be cleaned.
+ int[] regToRegRefCounts = {0, FINE / 2, 0, FINE, (FINE + COARSE) / 2, 0,
+ COARSE, COARSE + 10, FINE + 1, FINE / 2, 0};
+
+ // For progress tracking
+ int[] progress = new int[regToRegRefCounts.length];
+ progress[0] = 0;
+ for (int i = 1; i < regToRegRefCounts.length; i++) {
+ progress[i] = progress[i - 1] + Math.abs(regToRegRefCounts[i] - regToRegRefCounts[i - 1]);
+ }
+ try {
+ for (int i = 1; i < regToRegRefCounts.length; i++) {
+ int pre = regToRegRefCounts[i - 1];
+ int cur = regToRegRefCounts[i];
+ float prog = ((float) progress[i - 1] / progress[progress.length - 1]);
+
+ System.out.println("%% step " + i
+ + " out of " + (regToRegRefCounts.length - 1)
+ + " (~" + (int) (100 * prog) + "% done)");
+ System.out.println("%% " + pre + " --> " + cur);
+ for (int to = 0; to < regionCount; to++) {
+ // Select a celebrity object that we will install references to.
+ // The celebrity will be referred from all other regions.
+ // If the number of references after should be less than they
+ // were before, select NULL.
+ Object celebrity = cur > pre ? storage[to * K] : null;
+ for (int from = 0; from < regionCount; from++) {
+ if (to == from) {
+ continue; // no need to refer to itself
+ }
+
+ int step = cur > pre ? +1 : -1;
+ for (int rn = pre; rn != cur; rn += step) {
+ storage[getY(to, from, rn)][getX(to, from, rn)] = celebrity;
+ if (System.currentTimeMillis() > finishAt) {
+ throw new TimeoutException();
+ }
+ }
+ }
+ }
+ if (pre > cur) {
+ // Number of references went down.
+ // Need to provoke recalculation of RSet.
+ WB.g1StartConcMarkCycle();
+ while (WB.g1InConcurrentMark()) {
+ Thread.sleep(1);
+ }
+ }
+
+ // To force the use of rememebered set entries we need to provoke a GC.
+ // To induce some fragmentation, and some mixed GCs, we need
+ // to make a few objects unreachable.
+ for (int toClean = i * regsToRefresh; toClean < (i + 1) * regsToRefresh; toClean++) {
+ int to = toClean % regionCount;
+ // Need to remove all references from all regions to the region 'to'
+ for (int from = 0; from < regionCount; from++) {
+ if (to == from) {
+ continue; // no need to refer to itself
+ }
+ for (int rn = 0; rn <= cur; rn++) {
+ storage[getY(to, from, rn)][getX(to, from, rn)] = null;
+ }
+ }
+ // 'Refresh' storage elements for the region 'to'
+ // After that loop all 'old' objects in the region 'to'
+ // should become unreachable.
+ for (int k = 0; k < K; k++) {
+ storage[(to * K + k) % storage.length] = new Object[N];
+ }
+ }
+ }
+ } catch (TimeoutException e) {
+ System.out.println("%% TIMEOUT!!!");
+ }
+ long now = System.currentTimeMillis();
+ System.out.println("%% Summary");
+ System.out.println("%% Time spent : " + ((now - start) / 1000) + " seconds");
+ System.out.println("%% Free memory left : " + Runtime.getRuntime().freeMemory() / KB + "K");
+ System.out.println("%% Test passed");
+ }
+
+ /**
+ * Returns X index in the Storage of the reference #rn from the region
+ * 'from' to the region 'to'.
+ *
+ * @param to region # to refer to
+ * @param from region # to refer from
+ * @param rn number of reference
+ *
+ * @return X index in the range: [0 ... N-1]
+ */
+ private int getX(int to, int from, int rn) {
+ return (rn * regionCount + to) % N;
+ }
+
+ /**
+ * Returns Y index in the Storage of the reference #rn from the region
+ * 'from' to the region 'to'.
+ *
+ * @param to region # to refer to
+ * @param from region # to refer from
+ * @param rn number of reference
+ *
+ * @return Y index in the range: [0 ... K*regionCount -1]
+ */
+ private int getY(int to, int from, int rn) {
+ return ((rn * regionCount + to) / N + from * K) % (regionCount * K);
+ }
+}
+
--- a/hotspot/test/testlibrary/jittester/Makefile Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/testlibrary/jittester/Makefile Wed Jul 05 21:21:58 2017 +0200
@@ -35,6 +35,15 @@
TESTBASE_DIR := ws/hotspot/test
endif
+APPLICATION_ARGS =
+ifneq "x$(TESTS_NUMBER)" "x"
+ APPLICATION_ARGS += --number-of-tests $(TESTS_NUMBER)
+endif
+
+ifneq "x$(SEED)" "x"
+ APPLICATION_ARGS += --seed $(SEED)
+endif
+
JAVA = $(JDK_HOME)/bin/java
JAVAC = $(JDK_HOME)/bin/javac
JAR = $(JDK_HOME)/bin/jar
@@ -43,8 +52,9 @@
CLASSES_DIR = $(BUILD_DIR)/classes
SRC_DIR = src
TEST_DIR = test
+DRIVER_DIR = $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg
MANIFEST = manifest.mf
-APPLICATION_ARGS = \
+APPLICATION_ARGS += \
--property-file $(PROPERTY_FILE) \
--testbase-dir $(TESTBASE_DIR)
MAIN_CLASS = JitTestGenerator.Automatic
@@ -103,8 +113,8 @@
@rm filelist
@rm -rf $(CLASSES_DIR)
-copytestlibrary:
- @cp -r src/jdk/test/lib/jittester/jtreg $(TESTBASE_DIR)/
+copytestlibrary: $(DRIVER_DIR)
+ @cp -r src/jdk/test/lib/jittester/jtreg/*.java $(DRIVER_DIR)
@cp -r ../jdk $(TESTBASE_DIR)/
testgroup: $(TESTBASE_DIR)
@@ -117,9 +127,6 @@
testroot: $(TESTBASE_DIR)
@echo 'groups=TEST.groups' > $(TESTROOT_FILE)
-$(TESTBASE_DIR):
+$(TESTBASE_DIR) $(DIST_DIR) $(DRIVER_DIR):
$(shell if [ ! -d $@ ]; then mkdir -p $@; fi)
-$(DIST_DIR):
- $(shell if [ ! -d $@ ]; then mkdir -p $@; fi)
-
--- a/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java Mon Feb 22 09:02:14 2016 +0100
+++ b/hotspot/test/testlibrary_tests/whitebox/vm_flags/IntxTest.java Wed Jul 05 21:21:58 2017 +0200
@@ -23,14 +23,13 @@
/*
* @test IntxTest
- * @bug 8028756
- * @ignore 8148758
+ * @bug 8038756
* @library /testlibrary /test/lib
* @modules java.management/sun.management
* @build IntxTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-ProfileInterpreter IntxTest
+ * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xint -XX:-ProfileInterpreter IntxTest
* @summary testing of WB::set/getIntxVMFlag()
* @author igor.ignatyev@oracle.com
*/
--- a/make/Javadoc.gmk Mon Feb 22 09:02:14 2016 +0100
+++ b/make/Javadoc.gmk Wed Jul 05 21:21:58 2017 +0200
@@ -212,6 +212,11 @@
JRE_API_DOCSDIR = $(DOCSDIR)/jre/api
PLATFORM_DOCSDIR = $(DOCSDIR)/platform
+# The core api index file is the target for the core api javadocs rule
+# and needs to be defined early so that all other javadoc rules may
+# depend on it.
+COREAPI_INDEX_FILE = $(COREAPI_DOCSDIR)/index.html
+
# The non-core api javadocs need to be able to access the root of the core
# api directory, so for jdk/api or jre/api to get to the core api/
# directory we would use this:
@@ -363,8 +368,7 @@
# Overview file for core apis
COREAPI_OVERVIEW = $(JDK_TOPDIR)/src/java.base/share/classes/overview-core.html
-# The index.html, options, and packages files
-COREAPI_INDEX_FILE = $(COREAPI_DOCSDIR)/index.html
+# The options and packages files
COREAPI_OPTIONS_FILE = $(DOCSTMPDIR)/coredocs.options
COREAPI_PACKAGES_FILE = $(DOCSTMPDIR)/coredocs.packages
--- a/modules.xml Mon Feb 22 09:02:14 2016 +0100
+++ b/modules.xml Wed Jul 05 21:21:58 2017 +0200
@@ -239,6 +239,7 @@
<to>java.xml</to>
<to>jdk.charsets</to>
<to>jdk.management.resource</to>
+ <to>jdk.net</to>
<to>jdk.scripting.nashorn</to>
<to>jdk.vm.ci</to>
</export>
@@ -320,6 +321,10 @@
<to>jdk.naming.dns</to>
</export>
<export>
+ <name>sun.net.sdp</name>
+ <to>jdk.net</to>
+ </export>
+ <export>
<name>sun.net.spi.nameservice</name>
<to>jdk.naming.dns</to>
</export>
@@ -345,6 +350,7 @@
<to>jdk.crypto.pkcs11</to>
<to>jdk.crypto.ucrypto</to>
<to>jdk.management.resource</to>
+ <to>jdk.net</to>
<to>jdk.sctp</to>
</export>
<export>