--- a/make/autoconf/flags-cflags.m4 Tue Apr 17 08:54:17 2018 -0700
+++ b/make/autoconf/flags-cflags.m4 Tue Apr 17 18:18:53 2018 +0100
@@ -453,7 +453,7 @@
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
ALWAYS_DEFINES_JDK="-DWIN32_LEAN_AND_MEAN -D_CRT_SECURE_NO_DEPRECATE \
-D_CRT_NONSTDC_NO_DEPRECATE -DWIN32 -DIAL"
- ALWAYS_DEFINES_JVM="-DNOMINMAX"
+ ALWAYS_DEFINES_JVM="-DNOMINMAX -DWIN32_LEAN_AND_MEAN"
fi
###############################################################################
--- a/make/hotspot/lib/JvmOverrideFiles.gmk Tue Apr 17 08:54:17 2018 -0700
+++ b/make/hotspot/lib/JvmOverrideFiles.gmk Tue Apr 17 18:18:53 2018 +0100
@@ -34,6 +34,7 @@
BUILD_LIBJVM_jvmciCompilerToVM.cpp_CXXFLAGS := -fno-var-tracking-assignments
BUILD_LIBJVM_jvmciCompilerToVMInit.cpp_CXXFLAGS := -fno-var-tracking-assignments
BUILD_LIBJVM_assembler_x86.cpp_CXXFLAGS := -Wno-maybe-uninitialized
+ BUILD_LIBJVM_cardTableBarrierSetAssembler_x86.cpp_CXXFLAGS := -Wno-maybe-uninitialized
BUILD_LIBJVM_interp_masm_x86.cpp_CXXFLAGS := -Wno-uninitialized
endif
--- a/src/hotspot/cpu/aarch64/aarch64.ad Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/aarch64.ad Tue Apr 17 18:18:53 2018 +0100
@@ -5847,8 +5847,8 @@
operand immByteMapBase()
%{
// Get base of card map
- predicate(Universe::heap()->barrier_set()->is_a(BarrierSet::CardTableBarrierSet) &&
- (jbyte*)n->get_ptr() == ((CardTableBarrierSet*)(Universe::heap()->barrier_set()))->card_table()->byte_map_base());
+ predicate(BarrierSet::barrier_set()->is_a(BarrierSet::CardTableBarrierSet) &&
+ (jbyte*)n->get_ptr() == ((CardTableBarrierSet*)(BarrierSet::barrier_set()))->card_table()->byte_map_base());
match(ConP);
op_cost(0);
@@ -16167,9 +16167,8 @@
format %{ "String Equals $str1,$str2,$cnt -> $result" %}
ins_encode %{
// Count is in 8-bit bytes; non-Compact chars are 16 bits.
- __ arrays_equals($str1$$Register, $str2$$Register,
- $result$$Register, $cnt$$Register,
- 1, /*is_string*/true);
+ __ string_equals($str1$$Register, $str2$$Register,
+ $result$$Register, $cnt$$Register, 1);
%}
ins_pipe(pipe_class_memory);
%}
@@ -16184,42 +16183,42 @@
format %{ "String Equals $str1,$str2,$cnt -> $result" %}
ins_encode %{
// Count is in 8-bit bytes; non-Compact chars are 16 bits.
- __ asrw($cnt$$Register, $cnt$$Register, 1);
- __ arrays_equals($str1$$Register, $str2$$Register,
- $result$$Register, $cnt$$Register,
- 2, /*is_string*/true);
+ __ string_equals($str1$$Register, $str2$$Register,
+ $result$$Register, $cnt$$Register, 2);
%}
ins_pipe(pipe_class_memory);
%}
instruct array_equalsB(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result,
- iRegP_R10 tmp, rFlagsReg cr)
+ iRegP_R3 tmp1, iRegP_R4 tmp2, iRegP_R5 tmp3,
+ 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);
+ effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %}
ins_encode %{
__ arrays_equals($ary1$$Register, $ary2$$Register,
- $result$$Register, $tmp$$Register,
- 1, /*is_string*/false);
+ $tmp1$$Register, $tmp2$$Register, $tmp3$$Register,
+ $result$$Register, $tmp$$Register, 1);
%}
ins_pipe(pipe_class_memory);
%}
instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result,
- iRegP_R10 tmp, rFlagsReg cr)
+ iRegP_R3 tmp1, iRegP_R4 tmp2, iRegP_R5 tmp3,
+ iRegP_R10 tmp, rFlagsReg cr)
%{
predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU);
match(Set result (AryEq ary1 ary2));
- effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, KILL cr);
+ effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr);
format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %}
ins_encode %{
__ arrays_equals($ary1$$Register, $ary2$$Register,
- $result$$Register, $tmp$$Register,
- 2, /*is_string*/false);
+ $tmp1$$Register, $tmp2$$Register, $tmp3$$Register,
+ $result$$Register, $tmp$$Register, 2);
%}
ins_pipe(pipe_class_memory);
%}
--- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -819,7 +819,7 @@
void NAME(Register Rd, Register Rn, unsigned immr, unsigned imms) { \
starti; \
f(opcode, 31, 22), f(immr, 21, 16), f(imms, 15, 10); \
- rf(Rn, 5), rf(Rd, 0); \
+ zrf(Rn, 5), rf(Rd, 0); \
}
INSN(sbfmw, 0b0001001100);
--- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -46,6 +46,7 @@
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#endif
@@ -1106,7 +1107,7 @@
StubFrame f(sasm, "g1_pre_barrier", dont_gc_arguments);
// arg0 : previous value of memory
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ mov(r0, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), r0);
@@ -1118,13 +1119,9 @@
const Register thread = rthread;
const Register tmp = rscratch1;
- Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active()));
-
- Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_index()));
- Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf()));
+ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+ Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
+ Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
Label done;
Label runtime;
@@ -1162,7 +1159,7 @@
{
StubFrame f(sasm, "g1_post_barrier", dont_gc_arguments);
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ mov(r0, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), r0);
@@ -1181,10 +1178,8 @@
const Register thread = rthread;
- Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_index()));
- Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf()));
+ Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
+ Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
const Register card_offset = rscratch2;
// LR is free here, so we can use it to hold the byte_map_base.
--- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,12 +25,12 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "gc/g1/g1BarrierSet.hpp"
+#include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1BarrierSetAssembler.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
-#include "gc/shared/collectedHeap.hpp"
-#include "runtime/thread.hpp"
#include "interpreter/interp_masm.hpp"
+#include "runtime/sharedRuntime.hpp"
#define __ masm->
@@ -75,3 +75,233 @@
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSet::write_ref_array_post_entry), 2);
__ pop(saved_regs, sp);
}
+
+void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp,
+ bool tosca_live,
+ bool expand_call) {
+ // If expand_call is true then we expand the call_VM_leaf macro
+ // directly to skip generating the check by
+ // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
+
+ assert(thread == rthread, "must be");
+
+ Label done;
+ Label runtime;
+
+ assert_different_registers(obj, pre_val, tmp, rscratch1);
+ assert(pre_val != noreg && tmp != noreg, "expecting a register");
+
+ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+ Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
+ Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
+
+ // Is marking active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ ldrw(tmp, in_progress);
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ ldrb(tmp, in_progress);
+ }
+ __ cbzw(tmp, done);
+
+ // Do we need to load the previous value?
+ if (obj != noreg) {
+ __ load_heap_oop(pre_val, Address(obj, 0));
+ }
+
+ // Is the previous value null?
+ __ cbz(pre_val, done);
+
+ // Can we store original value in the thread's buffer?
+ // Is index == 0?
+ // (The index field is typed as size_t.)
+
+ __ ldr(tmp, index); // tmp := *index_adr
+ __ cbz(tmp, runtime); // tmp == 0?
+ // If yes, goto runtime
+
+ __ sub(tmp, tmp, wordSize); // tmp := tmp - wordSize
+ __ str(tmp, index); // *index_adr := tmp
+ __ ldr(rscratch1, buffer);
+ __ add(tmp, tmp, rscratch1); // tmp := tmp + *buffer_adr
+
+ // Record the previous value
+ __ str(pre_val, Address(tmp, 0));
+ __ b(done);
+
+ __ bind(runtime);
+ // save the live input values
+ RegSet saved = RegSet::of(pre_val);
+ if (tosca_live) saved += RegSet::of(r0);
+ if (obj != noreg) saved += RegSet::of(obj);
+
+ __ push(saved, sp);
+
+ // Calling the runtime using the regular call_VM_leaf mechanism generates
+ // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
+ // that checks that the *(rfp+frame::interpreter_frame_last_sp) == NULL.
+ //
+ // If we care generating the pre-barrier without a frame (e.g. in the
+ // intrinsified Reference.get() routine) then ebp might be pointing to
+ // the caller frame and so this check will most likely fail at runtime.
+ //
+ // Expanding the call directly bypasses the generation of the check.
+ // So when we do not have have a full interpreter frame on the stack
+ // expand_call should be passed true.
+
+ if (expand_call) {
+ assert(pre_val != c_rarg1, "smashed arg");
+ __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
+ } else {
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
+ }
+
+ __ pop(saved, sp);
+
+ __ bind(done);
+
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp,
+ Register tmp2) {
+ assert(thread == rthread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp, tmp2,
+ rscratch1);
+ assert(store_addr != noreg && new_val != noreg && tmp != noreg
+ && tmp2 != noreg, "expecting a register");
+
+ Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
+ Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
+
+ BarrierSet* bs = BarrierSet::barrier_set();
+ CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
+ CardTable* ct = ctbs->card_table();
+ assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
+
+ Label done;
+ Label runtime;
+
+ // Does store cross heap regions?
+
+ __ eor(tmp, store_addr, new_val);
+ __ lsr(tmp, tmp, HeapRegion::LogOfHRGrainBytes);
+ __ cbz(tmp, done);
+
+ // crosses regions, storing NULL?
+
+ __ cbz(new_val, done);
+
+ // storing region crossing non-NULL, is card already dirty?
+
+ ExternalAddress cardtable((address) ct->byte_map_base());
+ assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
+ const Register card_addr = tmp;
+
+ __ lsr(card_addr, store_addr, CardTable::card_shift);
+
+ // get the address of the card
+ __ load_byte_map_base(tmp2);
+ __ add(card_addr, card_addr, tmp2);
+ __ ldrb(tmp2, Address(card_addr));
+ __ cmpw(tmp2, (int)G1CardTable::g1_young_card_val());
+ __ br(Assembler::EQ, done);
+
+ assert((int)CardTable::dirty_card_val() == 0, "must be 0");
+
+ __ membar(Assembler::StoreLoad);
+
+ __ ldrb(tmp2, Address(card_addr));
+ __ cbzw(tmp2, done);
+
+ // storing a region crossing, non-NULL oop, card is clean.
+ // dirty card and log.
+
+ __ strb(zr, Address(card_addr));
+
+ __ ldr(rscratch1, queue_index);
+ __ cbz(rscratch1, runtime);
+ __ sub(rscratch1, rscratch1, wordSize);
+ __ str(rscratch1, queue_index);
+
+ __ ldr(tmp2, buffer);
+ __ str(card_addr, Address(tmp2, rscratch1));
+ __ b(done);
+
+ __ bind(runtime);
+ // save the live input values
+ RegSet saved = RegSet::of(store_addr, new_val);
+ __ push(saved, sp);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
+ __ pop(saved, sp);
+
+ __ bind(done);
+}
+
+void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register dst, Address src, Register tmp1, Register tmp_thread) {
+ bool on_oop = type == T_OBJECT || type == T_ARRAY;
+ bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
+ bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
+ bool on_reference = on_weak || on_phantom;
+ ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
+ if (on_oop && on_reference) {
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer.
+ g1_write_barrier_pre(masm /* masm */,
+ noreg /* obj */,
+ dst /* pre_val */,
+ rthread /* thread */,
+ tmp1 /* tmp */,
+ true /* tosca_live */,
+ true /* expand_call */);
+ }
+}
+
+void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2) {
+ // flatten object address if needed
+ if (dst.index() == noreg && dst.offset() == 0) {
+ if (dst.base() != r3) {
+ __ mov(r3, dst.base());
+ }
+ } else {
+ __ lea(r3, dst);
+ }
+
+ g1_write_barrier_pre(masm,
+ r3 /* obj */,
+ tmp2 /* pre_val */,
+ rthread /* thread */,
+ tmp1 /* tmp */,
+ val != noreg /* tosca_live */,
+ false /* expand_call */);
+
+ if (val == noreg) {
+ __ store_heap_oop_null(Address(r3, 0));
+ } else {
+ // G1 barrier needs uncompressed oop for region cross check.
+ Register new_val = val;
+ if (UseCompressedOops) {
+ new_val = rscratch2;
+ __ mov(new_val, val);
+ }
+ __ store_heap_oop(Address(r3, 0), val);
+ g1_write_barrier_post(masm,
+ r3 /* store_adr */,
+ new_val /* new_val */,
+ rthread /* thread */,
+ tmp1 /* tmp */,
+ tmp2 /* tmp2 */);
+ }
+
+}
+
+#undef __
--- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -34,6 +34,28 @@
Register addr, Register count, RegSet saved_regs);
void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register start, Register end, Register tmp, RegSet saved_regs);
+
+ void g1_write_barrier_pre(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp,
+ bool tosca_live,
+ bool expand_call);
+
+ void g1_write_barrier_post(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp,
+ Register tmp2);
+
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2);
+
+public:
+ void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register dst, Address src, Register tmp1, Register tmp_thread);
};
#endif // CPU_AARCH64_GC_G1_G1BARRIERSETASSEMBLER_AARCH64_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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/shared/barrierSetAssembler.hpp"
+
+#define __ masm->
+
+void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register dst, Address src, Register tmp1, Register tmp_thread) {
+ bool on_heap = (decorators & IN_HEAP) != 0;
+ bool on_root = (decorators & IN_ROOT) != 0;
+ switch (type) {
+ case T_OBJECT:
+ case T_ARRAY: {
+ if (on_heap) {
+ __ load_heap_oop(dst, src);
+ } else {
+ assert(on_root, "why else?");
+ __ ldr(dst, src);
+ }
+ break;
+ }
+ default: Unimplemented();
+ }
+}
+
+void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2) {
+ bool on_heap = (decorators & IN_HEAP) != 0;
+ bool on_root = (decorators & IN_ROOT) != 0;
+ switch (type) {
+ case T_OBJECT:
+ case T_ARRAY: {
+ if (on_heap) {
+ __ store_heap_oop(dst, val);
+ } else {
+ assert(on_root, "why else?");
+ __ str(val, dst);
+ }
+ break;
+ }
+ default: Unimplemented();
+ }
+}
--- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -35,6 +35,12 @@
Register addr, Register count, RegSet saved_regs) {}
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register start, Register end, Register tmp, RegSet saved_regs) {}
+ virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register dst, Address src, Register tmp1, Register tmp_thread);
+ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2);
+
+ virtual void barrier_stubs_init() {}
};
#endif // CPU_AARCH64_GC_SHARED_BARRIERSETASSEMBLER_AARCH64_HPP
--- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,15 +28,44 @@
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/cardTableBarrierSetAssembler.hpp"
-#include "gc/shared/collectedHeap.hpp"
#include "interpreter/interp_masm.hpp"
#define __ masm->
+
+void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Address dst) {
+
+ BarrierSet* bs = BarrierSet::barrier_set();
+ assert(bs->kind() == BarrierSet::CardTableBarrierSet, "Wrong barrier set kind");
+
+ CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
+ CardTable* ct = ctbs->card_table();
+ assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
+
+ __ lsr(obj, obj, CardTable::card_shift);
+
+ assert(CardTable::dirty_card_val() == 0, "must be");
+
+ __ load_byte_map_base(rscratch1);
+
+ if (UseCondCardMark) {
+ Label L_already_dirty;
+ __ membar(Assembler::StoreLoad);
+ __ ldrb(rscratch2, Address(obj, rscratch1));
+ __ cbz(rscratch2, L_already_dirty);
+ __ strb(zr, Address(obj, rscratch1));
+ __ bind(L_already_dirty);
+ } else {
+ if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
+ __ membar(Assembler::StoreStore);
+ }
+ __ strb(zr, Address(obj, rscratch1));
+ }
+}
+
void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register start, Register end, Register scratch, RegSet saved_regs) {
-
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
@@ -58,3 +87,22 @@
__ subs(count, count, 1);
__ br(Assembler::GE, L_loop);
}
+
+void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2) {
+ bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
+ bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
+ bool precise = on_array || on_anonymous;
+ if (val == noreg) {
+ __ store_heap_oop_null(dst);
+ } else {
+ __ store_heap_oop(dst, val);
+ // flatten object address if needed
+ if (!precise || (dst.index() == noreg && dst.offset() == 0)) {
+ store_check(masm, dst.base(), dst);
+ } else {
+ __ lea(r3, dst);
+ store_check(masm, r3, dst);
+ }
+ }
+}
--- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,8 +30,13 @@
class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
+ void store_check(MacroAssembler* masm, Register obj, Address dst);
+
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register start, Register end, Register tmp, RegSet saved_regs);
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2);
+
};
#endif // #ifndef CPU_AARCH64_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_AARCH64_HPP
--- a/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -43,3 +43,18 @@
gen_write_ref_array_post_barrier(masm, decorators, start, end, tmp, saved_regs);
}
}
+
+
+void ModRefBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2) {
+ BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2);
+}
+
+void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2) {
+ if (type == T_OBJECT || type == T_ARRAY) {
+ oop_store_at(masm, decorators, type, dst, val, tmp1, tmp2);
+ } else {
+ BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2);
+ }
+}
--- a/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,6 +28,10 @@
#include "asm/macroAssembler.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
+// The ModRefBarrierSetAssembler filters away accesses on BasicTypes other
+// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected
+// accesses, which are overridden in the concrete BarrierSetAssembler.
+
class ModRefBarrierSetAssembler: public BarrierSetAssembler {
protected:
virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
@@ -35,11 +39,16 @@
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register start, Register end, Register tmp, RegSet saved_regs) {}
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2);
+
public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register addr, Register count, RegSet saved_regs);
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register start, Register end, Register tmp, RegSet saved_regs);
+ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2);
};
#endif // CPU_AARCH64_GC_SHARED_MODREFBARRIERSETASSEMBLER_AARCH64_HPP
--- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -147,6 +147,10 @@
"Use CRC32 instructions for CRC32 computation") \
product(bool, UseSIMDForMemoryOps, false, \
"Use SIMD instructions in generated memory move code") \
+ product(bool, UseSIMDForArrayEquals, true, \
+ "Use SIMD instructions in generated array equals code") \
+ product(bool, UseSimpleArrayEquals, false, \
+ "Use simpliest and shortest implementation for array equals") \
product(bool, AvoidUnalignedAccesses, false, \
"Avoid generating unaligned memory accesses") \
product(bool, UseLSE, false, \
--- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -24,6 +24,8 @@
*/
#include "precompiled.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interp_masm_aarch64.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
@@ -277,9 +279,8 @@
resolve_oop_handle(result);
// Add in the index
add(result, result, tmp);
- load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
- // The resulting oop is null if the reference is not yet resolved.
- // It is Universe::the_null_sentinel() if the reference resolved to NULL via condy.
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->load_at(this, IN_HEAP, T_OBJECT, result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT)), /*tmp1*/ noreg, /*tmp_thread*/ noreg);
}
void InterpreterMacroAssembler::load_resolved_klass_at_offset(
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -29,7 +29,9 @@
#include "jvm.h"
#include "asm/assembler.hpp"
#include "asm/assembler.inline.hpp"
+#include "gc/shared/barrierSet.hpp"
#include "gc/shared/cardTable.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "interpreter/interpreter.hpp"
#include "compiler/disassembler.hpp"
@@ -50,7 +52,6 @@
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/heapRegion.hpp"
#endif
@@ -2091,6 +2092,28 @@
}
#endif
+void MacroAssembler::resolve_jobject(Register value, Register thread, Register tmp) {
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ Label done, not_weak;
+ cbz(value, done); // Use NULL as-is.
+
+ STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u);
+ tbz(r0, 0, not_weak); // Test for jweak tag.
+
+ // Resolve jweak.
+ bs->load_at(this, IN_ROOT | ON_PHANTOM_OOP_REF, T_OBJECT,
+ value, Address(value, -JNIHandles::weak_tag_value), tmp, thread);
+ verify_oop(value);
+ b(done);
+
+ bind(not_weak);
+ // Resolve (untagged) jobject.
+ bs->load_at(this, IN_ROOT | ON_STRONG_OOP_REF, T_OBJECT,
+ value, Address(value, 0), tmp, thread);
+ verify_oop(value);
+ bind(done);
+}
+
void MacroAssembler::stop(const char* msg) {
address ip = pc();
pusha();
@@ -3609,43 +3632,6 @@
cmp(src1, rscratch1);
}
-void MacroAssembler::store_check(Register obj, Address dst) {
- store_check(obj);
-}
-
-void MacroAssembler::store_check(Register obj) {
- // Does a store check for the oop in register obj. The content of
- // register obj is destroyed afterwards.
-
- BarrierSet* bs = Universe::heap()->barrier_set();
- assert(bs->kind() == BarrierSet::CardTableBarrierSet,
- "Wrong barrier set kind");
-
- CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
- CardTable* ct = ctbs->card_table();
- assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
-
- lsr(obj, obj, CardTable::card_shift);
-
- assert(CardTable::dirty_card_val() == 0, "must be");
-
- load_byte_map_base(rscratch1);
-
- if (UseCondCardMark) {
- Label L_already_dirty;
- membar(StoreLoad);
- ldrb(rscratch2, Address(obj, rscratch1));
- cbz(rscratch2, L_already_dirty);
- strb(zr, Address(obj, rscratch1));
- bind(L_already_dirty);
- } else {
- if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
- membar(StoreStore);
- }
- strb(zr, Address(obj, rscratch1));
- }
-}
-
void MacroAssembler::load_klass(Register dst, Register src) {
if (UseCompressedClassPointers) {
ldrw(dst, Address(src, oopDesc::klass_offset_in_bytes()));
@@ -4009,190 +3995,6 @@
str(zr, dst);
}
-#if INCLUDE_ALL_GCS
-/*
- * g1_write_barrier_pre -- G1GC pre-write barrier for store of new_val at
- * store_addr.
- *
- * Allocates rscratch1
- */
-void MacroAssembler::g1_write_barrier_pre(Register obj,
- Register pre_val,
- Register thread,
- Register tmp,
- bool tosca_live,
- bool expand_call) {
- // If expand_call is true then we expand the call_VM_leaf macro
- // directly to skip generating the check by
- // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
-
- assert(thread == rthread, "must be");
-
- Label done;
- Label runtime;
-
- assert_different_registers(obj, pre_val, tmp, rscratch1);
- assert(pre_val != noreg && tmp != noreg, "expecting a register");
-
- Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active()));
- Address index(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_index()));
- Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf()));
-
-
- // Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- ldrw(tmp, in_progress);
- } else {
- assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- ldrb(tmp, in_progress);
- }
- cbzw(tmp, done);
-
- // Do we need to load the previous value?
- if (obj != noreg) {
- load_heap_oop(pre_val, Address(obj, 0));
- }
-
- // Is the previous value null?
- cbz(pre_val, done);
-
- // Can we store original value in the thread's buffer?
- // Is index == 0?
- // (The index field is typed as size_t.)
-
- ldr(tmp, index); // tmp := *index_adr
- cbz(tmp, runtime); // tmp == 0?
- // If yes, goto runtime
-
- sub(tmp, tmp, wordSize); // tmp := tmp - wordSize
- str(tmp, index); // *index_adr := tmp
- ldr(rscratch1, buffer);
- add(tmp, tmp, rscratch1); // tmp := tmp + *buffer_adr
-
- // Record the previous value
- str(pre_val, Address(tmp, 0));
- b(done);
-
- bind(runtime);
- // save the live input values
- push(r0->bit(tosca_live) | obj->bit(obj != noreg) | pre_val->bit(true), sp);
-
- // Calling the runtime using the regular call_VM_leaf mechanism generates
- // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
- // that checks that the *(rfp+frame::interpreter_frame_last_sp) == NULL.
- //
- // If we care generating the pre-barrier without a frame (e.g. in the
- // intrinsified Reference.get() routine) then ebp might be pointing to
- // the caller frame and so this check will most likely fail at runtime.
- //
- // Expanding the call directly bypasses the generation of the check.
- // So when we do not have have a full interpreter frame on the stack
- // expand_call should be passed true.
-
- if (expand_call) {
- assert(pre_val != c_rarg1, "smashed arg");
- pass_arg1(this, thread);
- pass_arg0(this, pre_val);
- MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), 2);
- } else {
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
- }
-
- pop(r0->bit(tosca_live) | obj->bit(obj != noreg) | pre_val->bit(true), sp);
-
- bind(done);
-}
-
-/*
- * g1_write_barrier_post -- G1GC post-write barrier for store of new_val at
- * store_addr
- *
- * Allocates rscratch1
- */
-void MacroAssembler::g1_write_barrier_post(Register store_addr,
- Register new_val,
- Register thread,
- Register tmp,
- Register tmp2) {
- assert(thread == rthread, "must be");
- assert_different_registers(store_addr, new_val, thread, tmp, tmp2,
- rscratch1);
- assert(store_addr != noreg && new_val != noreg && tmp != noreg
- && tmp2 != noreg, "expecting a register");
-
- Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_index()));
- Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf()));
-
- BarrierSet* bs = Universe::heap()->barrier_set();
- CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
- CardTable* ct = ctbs->card_table();
- assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
-
- Label done;
- Label runtime;
-
- // Does store cross heap regions?
-
- eor(tmp, store_addr, new_val);
- lsr(tmp, tmp, HeapRegion::LogOfHRGrainBytes);
- cbz(tmp, done);
-
- // crosses regions, storing NULL?
-
- cbz(new_val, done);
-
- // storing region crossing non-NULL, is card already dirty?
-
- ExternalAddress cardtable((address) ct->byte_map_base());
- assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
- const Register card_addr = tmp;
-
- lsr(card_addr, store_addr, CardTable::card_shift);
-
- // get the address of the card
- load_byte_map_base(tmp2);
- add(card_addr, card_addr, tmp2);
- ldrb(tmp2, Address(card_addr));
- cmpw(tmp2, (int)G1CardTable::g1_young_card_val());
- br(Assembler::EQ, done);
-
- assert((int)CardTable::dirty_card_val() == 0, "must be 0");
-
- membar(Assembler::StoreLoad);
-
- ldrb(tmp2, Address(card_addr));
- cbzw(tmp2, done);
-
- // storing a region crossing, non-NULL oop, card is clean.
- // dirty card and log.
-
- strb(zr, Address(card_addr));
-
- ldr(rscratch1, queue_index);
- cbz(rscratch1, runtime);
- sub(rscratch1, rscratch1, wordSize);
- str(rscratch1, queue_index);
-
- ldr(tmp2, buffer);
- str(card_addr, Address(tmp2, rscratch1));
- b(done);
-
- bind(runtime);
- // save the live input values
- push(store_addr->bit(true) | new_val->bit(true), sp);
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
- pop(store_addr->bit(true) | new_val->bit(true), sp);
-
- bind(done);
-}
-
-#endif // INCLUDE_ALL_GCS
-
Address MacroAssembler::allocate_metadata_address(Metadata* obj) {
assert(oop_recorder() != NULL, "this assembler needs a Recorder");
int index = oop_recorder()->allocate_metadata_index(obj);
@@ -4515,7 +4317,7 @@
void MacroAssembler::load_byte_map_base(Register reg) {
jbyte *byte_map_base =
- ((CardTableBarrierSet*)(Universe::heap()->barrier_set()))->card_table()->byte_map_base();
+ ((CardTableBarrierSet*)(BarrierSet::barrier_set()))->card_table()->byte_map_base();
if (is_valid_AArch64_address((address)byte_map_base)) {
// Strictly speaking the byte_map_base isn't an address at all,
@@ -5182,28 +4984,11 @@
BIND(DONE);
}
-// Compare Strings or char/byte arrays.
-
-// is_string is true iff this is a string comparison.
-
-// For Strings we're passed the address of the first characters in a1
-// and a2 and the length in cnt1.
-
-// For byte and char arrays we're passed the arrays themselves and we
-// have to extract length fields and do null checks here.
-
-// elem_size is the element size in bytes: either 1 or 2.
-
-// There are two implementations. For arrays >= 8 bytes, all
-// comparisons (including the final one, which may overlap) are
-// performed 8 bytes at a time. For arrays < 8 bytes, we compare a
-// halfword, then a short, and then a byte.
-
-void MacroAssembler::arrays_equals(Register a1, Register a2,
- Register result, Register cnt1,
- int elem_size, bool is_string)
+void MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3,
+ Register tmp4, Register tmp5, Register result,
+ Register cnt1, int elem_size)
{
- Label SAME, DONE, SHORT, NEXT_WORD, ONE;
+ Label DONE;
Register tmp1 = rscratch1;
Register tmp2 = rscratch2;
Register cnt2 = tmp2; // cnt2 only used in array length compare
@@ -5212,6 +4997,7 @@
int length_offset = arrayOopDesc::length_offset_in_bytes();
int base_offset
= arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE);
+ int stubBytesThreshold = 3 * 64 + (UseSIMDForArrayEquals ? 0 : 16);
assert(elem_size == 1 || elem_size == 2, "must be char or byte");
assert_different_registers(a1, a2, result, cnt1, rscratch1, rscratch2);
@@ -5220,43 +5006,229 @@
{
const char kind = (elem_size == 2) ? 'U' : 'L';
char comment[64];
- snprintf(comment, sizeof comment, "%s%c%s {",
- is_string ? "string_equals" : "array_equals",
- kind, "{");
+ snprintf(comment, sizeof comment, "array_equals%c{", kind);
+ BLOCK_COMMENT(comment);
+ }
+#endif
+ if (UseSimpleArrayEquals) {
+ Label NEXT_WORD, SHORT, SAME, TAIL03, TAIL01, A_MIGHT_BE_NULL, A_IS_NOT_NULL;
+ // if (a1==a2)
+ // return true;
+ // if (a==null || a2==null)
+ // return false;
+ // a1 & a2 == 0 means (some-pointer is null) or
+ // (very-rare-or-even-probably-impossible-pointer-values)
+ // so, we can save one branch in most cases
+ eor(rscratch1, a1, a2);
+ tst(a1, a2);
+ mov(result, false);
+ cbz(rscratch1, SAME);
+ br(EQ, A_MIGHT_BE_NULL);
+ // if (a1.length != a2.length)
+ // return false;
+ bind(A_IS_NOT_NULL);
+ ldrw(cnt1, Address(a1, length_offset));
+ ldrw(cnt2, Address(a2, length_offset));
+ eorw(tmp5, cnt1, cnt2);
+ cbnzw(tmp5, DONE);
+ lea(a1, Address(a1, base_offset));
+ lea(a2, Address(a2, base_offset));
+ // Check for short strings, i.e. smaller than wordSize.
+ subs(cnt1, cnt1, elem_per_word);
+ br(Assembler::LT, SHORT);
+ // Main 8 byte comparison loop.
+ bind(NEXT_WORD); {
+ ldr(tmp1, Address(post(a1, wordSize)));
+ ldr(tmp2, Address(post(a2, wordSize)));
+ subs(cnt1, cnt1, elem_per_word);
+ eor(tmp5, tmp1, tmp2);
+ cbnz(tmp5, DONE);
+ } br(GT, NEXT_WORD);
+ // Last longword. In the case where length == 4 we compare the
+ // same longword twice, but that's still faster than another
+ // conditional branch.
+ // cnt1 could be 0, -1, -2, -3, -4 for chars; -4 only happens when
+ // length == 4.
+ if (log_elem_size > 0)
+ lsl(cnt1, cnt1, log_elem_size);
+ ldr(tmp3, Address(a1, cnt1));
+ ldr(tmp4, Address(a2, cnt1));
+ eor(tmp5, tmp3, tmp4);
+ cbnz(tmp5, DONE);
+ b(SAME);
+ bind(A_MIGHT_BE_NULL);
+ // in case both a1 and a2 are not-null, proceed with loads
+ cbz(a1, DONE);
+ cbz(a2, DONE);
+ b(A_IS_NOT_NULL);
+ bind(SHORT);
+
+ tbz(cnt1, 2 - log_elem_size, TAIL03); // 0-7 bytes left.
+ {
+ ldrw(tmp1, Address(post(a1, 4)));
+ ldrw(tmp2, Address(post(a2, 4)));
+ eorw(tmp5, tmp1, tmp2);
+ cbnzw(tmp5, DONE);
+ }
+ bind(TAIL03);
+ tbz(cnt1, 1 - log_elem_size, TAIL01); // 0-3 bytes left.
+ {
+ ldrh(tmp3, Address(post(a1, 2)));
+ ldrh(tmp4, Address(post(a2, 2)));
+ eorw(tmp5, tmp3, tmp4);
+ cbnzw(tmp5, DONE);
+ }
+ bind(TAIL01);
+ if (elem_size == 1) { // Only needed when comparing byte arrays.
+ tbz(cnt1, 0, SAME); // 0-1 bytes left.
+ {
+ ldrb(tmp1, a1);
+ ldrb(tmp2, a2);
+ eorw(tmp5, tmp1, tmp2);
+ cbnzw(tmp5, DONE);
+ }
+ }
+ bind(SAME);
+ mov(result, true);
+ } else {
+ Label NEXT_DWORD, A_IS_NULL, SHORT, TAIL, TAIL2, STUB, EARLY_OUT,
+ CSET_EQ, LAST_CHECK, LEN_IS_ZERO, SAME;
+ cbz(a1, A_IS_NULL);
+ ldrw(cnt1, Address(a1, length_offset));
+ cbz(a2, A_IS_NULL);
+ ldrw(cnt2, Address(a2, length_offset));
+ mov(result, false);
+ // on most CPUs a2 is still "locked"(surprisingly) in ldrw and it's
+ // faster to perform another branch before comparing a1 and a2
+ cmp(cnt1, elem_per_word);
+ br(LE, SHORT); // short or same
+ cmp(a1, a2);
+ br(EQ, SAME);
+ ldr(tmp3, Address(pre(a1, base_offset)));
+ cmp(cnt1, stubBytesThreshold);
+ br(GE, STUB);
+ ldr(tmp4, Address(pre(a2, base_offset)));
+ sub(tmp5, zr, cnt1, LSL, 3 + log_elem_size);
+ cmp(cnt2, cnt1);
+ br(NE, DONE);
+
+ // Main 16 byte comparison loop with 2 exits
+ bind(NEXT_DWORD); {
+ ldr(tmp1, Address(pre(a1, wordSize)));
+ ldr(tmp2, Address(pre(a2, wordSize)));
+ subs(cnt1, cnt1, 2 * elem_per_word);
+ br(LE, TAIL);
+ eor(tmp4, tmp3, tmp4);
+ cbnz(tmp4, DONE);
+ ldr(tmp3, Address(pre(a1, wordSize)));
+ ldr(tmp4, Address(pre(a2, wordSize)));
+ cmp(cnt1, elem_per_word);
+ br(LE, TAIL2);
+ cmp(tmp1, tmp2);
+ } br(EQ, NEXT_DWORD);
+ b(DONE);
+
+ bind(TAIL);
+ eor(tmp4, tmp3, tmp4);
+ eor(tmp2, tmp1, tmp2);
+ lslv(tmp2, tmp2, tmp5);
+ orr(tmp5, tmp4, tmp2);
+ cmp(tmp5, zr);
+ b(CSET_EQ);
+
+ bind(TAIL2);
+ eor(tmp2, tmp1, tmp2);
+ cbnz(tmp2, DONE);
+ b(LAST_CHECK);
+
+ bind(STUB);
+ ldr(tmp4, Address(pre(a2, base_offset)));
+ cmp(cnt2, cnt1);
+ br(NE, DONE);
+ if (elem_size == 2) { // convert to byte counter
+ lsl(cnt1, cnt1, 1);
+ }
+ eor(tmp5, tmp3, tmp4);
+ cbnz(tmp5, DONE);
+ RuntimeAddress stub = RuntimeAddress(StubRoutines::aarch64::large_array_equals());
+ assert(stub.target() != NULL, "array_equals_long stub has not been generated");
+ trampoline_call(stub);
+ b(DONE);
+
+ bind(SAME);
+ mov(result, true);
+ b(DONE);
+ bind(A_IS_NULL);
+ // a1 or a2 is null. if a2 == a2 then return true. else return false
+ cmp(a1, a2);
+ b(CSET_EQ);
+ bind(EARLY_OUT);
+ // (a1 != null && a2 == null) || (a1 != null && a2 != null && a1 == a2)
+ // so, if a2 == null => return false(0), else return true, so we can return a2
+ mov(result, a2);
+ b(DONE);
+ bind(LEN_IS_ZERO);
+ cmp(cnt2, zr);
+ b(CSET_EQ);
+ bind(SHORT);
+ cbz(cnt1, LEN_IS_ZERO);
+ sub(tmp5, zr, cnt1, LSL, 3 + log_elem_size);
+ ldr(tmp3, Address(a1, base_offset));
+ ldr(tmp4, Address(a2, base_offset));
+ bind(LAST_CHECK);
+ eor(tmp4, tmp3, tmp4);
+ lslv(tmp5, tmp4, tmp5);
+ cmp(tmp5, zr);
+ bind(CSET_EQ);
+ cset(result, EQ);
+ }
+
+ // That's it.
+ bind(DONE);
+
+ BLOCK_COMMENT("} array_equals");
+}
+
+// Compare Strings
+
+// For Strings we're passed the address of the first characters in a1
+// and a2 and the length in cnt1.
+// elem_size is the element size in bytes: either 1 or 2.
+// There are two implementations. For arrays >= 8 bytes, all
+// comparisons (including the final one, which may overlap) are
+// performed 8 bytes at a time. For strings < 8 bytes, we compare a
+// halfword, then a short, and then a byte.
+
+void MacroAssembler::string_equals(Register a1, Register a2,
+ Register result, Register cnt1, int elem_size)
+{
+ Label SAME, DONE, SHORT, NEXT_WORD;
+ Register tmp1 = rscratch1;
+ Register tmp2 = rscratch2;
+ Register cnt2 = tmp2; // cnt2 only used in array length compare
+
+ assert(elem_size == 1 || elem_size == 2, "must be 2 or 1 byte");
+ assert_different_registers(a1, a2, result, cnt1, rscratch1, rscratch2);
+
+#ifndef PRODUCT
+ {
+ const char kind = (elem_size == 2) ? 'U' : 'L';
+ char comment[64];
+ snprintf(comment, sizeof comment, "{string_equals%c", kind);
BLOCK_COMMENT(comment);
}
#endif
mov(result, false);
- if (!is_string) {
- // if (a==a2)
- // return true;
- eor(rscratch1, a1, a2);
- cbz(rscratch1, SAME);
- // if (a==null || a2==null)
- // return false;
- cbz(a1, DONE);
- cbz(a2, DONE);
- // if (a1.length != a2.length)
- // return false;
- ldrw(cnt1, Address(a1, length_offset));
- ldrw(cnt2, Address(a2, length_offset));
- eorw(tmp1, cnt1, cnt2);
- cbnzw(tmp1, DONE);
-
- lea(a1, Address(a1, base_offset));
- lea(a2, Address(a2, base_offset));
- }
-
// Check for short strings, i.e. smaller than wordSize.
- subs(cnt1, cnt1, elem_per_word);
+ subs(cnt1, cnt1, wordSize);
br(Assembler::LT, SHORT);
// Main 8 byte comparison loop.
bind(NEXT_WORD); {
ldr(tmp1, Address(post(a1, wordSize)));
ldr(tmp2, Address(post(a2, wordSize)));
- subs(cnt1, cnt1, elem_per_word);
+ subs(cnt1, cnt1, wordSize);
eor(tmp1, tmp1, tmp2);
cbnz(tmp1, DONE);
} br(GT, NEXT_WORD);
@@ -5265,18 +5237,16 @@
// conditional branch.
// cnt1 could be 0, -1, -2, -3, -4 for chars; -4 only happens when
// length == 4.
- if (log_elem_size > 0)
- lsl(cnt1, cnt1, log_elem_size);
ldr(tmp1, Address(a1, cnt1));
ldr(tmp2, Address(a2, cnt1));
- eor(tmp1, tmp1, tmp2);
- cbnz(tmp1, DONE);
+ eor(tmp2, tmp1, tmp2);
+ cbnz(tmp2, DONE);
b(SAME);
bind(SHORT);
Label TAIL03, TAIL01;
- tbz(cnt1, 2 - log_elem_size, TAIL03); // 0-7 bytes left.
+ tbz(cnt1, 2, TAIL03); // 0-7 bytes left.
{
ldrw(tmp1, Address(post(a1, 4)));
ldrw(tmp2, Address(post(a2, 4)));
@@ -5284,7 +5254,7 @@
cbnzw(tmp1, DONE);
}
bind(TAIL03);
- tbz(cnt1, 1 - log_elem_size, TAIL01); // 0-3 bytes left.
+ tbz(cnt1, 1, TAIL01); // 0-3 bytes left.
{
ldrh(tmp1, Address(post(a1, 2)));
ldrh(tmp2, Address(post(a2, 2)));
@@ -5292,7 +5262,7 @@
cbnzw(tmp1, DONE);
}
bind(TAIL01);
- if (elem_size == 1) { // Only needed when comparing byte arrays.
+ if (elem_size == 1) { // Only needed when comparing 1-byte elements
tbz(cnt1, 0, SAME); // 0-1 bytes left.
{
ldrb(tmp1, a1);
@@ -5307,7 +5277,7 @@
// That's it.
bind(DONE);
- BLOCK_COMMENT(is_string ? "} string_equals" : "} array_equals");
+ BLOCK_COMMENT("} string_equals");
}
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, 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.
*
@@ -779,6 +779,8 @@
void store_check(Register obj); // store check for obj - register is destroyed afterwards
void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed)
+ void resolve_jobject(Register value, Register thread, Register tmp);
+
#if INCLUDE_ALL_GCS
void g1_write_barrier_pre(Register obj,
@@ -1225,9 +1227,11 @@
void has_negatives(Register ary1, Register len, Register result);
- void arrays_equals(Register a1, Register a2,
- Register result, Register cnt1,
- int elem_size, bool is_string);
+ void arrays_equals(Register a1, Register a2, Register result, Register cnt1,
+ Register tmp1, Register tmp2, Register tmp3, int elem_size);
+
+ void string_equals(Register a1, Register a2, Register result, Register cnt1,
+ int elem_size);
void fill_words(Register base, Register cnt, Register value);
void zero_words(Register base, u_int64_t cnt);
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, 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.
*
@@ -2050,29 +2050,7 @@
// Unbox oop result, e.g. JNIHandles::resolve result.
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
- Label done, not_weak;
- __ cbz(r0, done); // Use NULL as-is.
- STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u);
- __ tbz(r0, 0, not_weak); // Test for jweak tag.
- // Resolve jweak.
- __ ldr(r0, Address(r0, -JNIHandles::weak_tag_value));
- __ verify_oop(r0);
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- __ g1_write_barrier_pre(noreg /* obj */,
- r0 /* pre_val */,
- rthread /* thread */,
- rscratch2 /* tmp */,
- true /* tosca_live */,
- true /* expand_call */);
- }
-#endif // INCLUDE_ALL_GCS
- __ b(done);
- __ bind(not_weak);
- // Resolve (untagged) jobject.
- __ ldr(r0, Address(r0, 0));
- __ verify_oop(r0);
- __ bind(done);
+ __ resolve_jobject(r0, rthread, rscratch2);
}
if (CheckJNICalls) {
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1359,7 +1359,7 @@
decorators |= ARRAYCOPY_ALIGNED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, is_oop, d, count, saved_reg);
if (is_oop) {
@@ -1433,7 +1433,7 @@
decorators |= ARRAYCOPY_ALIGNED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, is_oop, d, count, saved_regs);
if (is_oop) {
@@ -1795,7 +1795,7 @@
decorators |= AS_DEST_NOT_INITIALIZED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, is_oop, to, count, wb_pre_saved_regs);
// save the original count
@@ -3813,6 +3813,182 @@
__ ret(lr);
return entry;
}
+
+ void generate_large_array_equals_loop_nonsimd(int loopThreshold,
+ bool usePrefetch, Label &NOT_EQUAL) {
+ Register a1 = r1, a2 = r2, result = r0, cnt1 = r10, tmp1 = rscratch1,
+ tmp2 = rscratch2, tmp3 = r3, tmp4 = r4, tmp5 = r5, tmp6 = r11,
+ tmp7 = r12, tmp8 = r13;
+ Label LOOP;
+
+ __ ldp(tmp1, tmp3, Address(__ post(a1, 2 * wordSize)));
+ __ ldp(tmp2, tmp4, Address(__ post(a2, 2 * wordSize)));
+ __ bind(LOOP);
+ if (usePrefetch) {
+ __ prfm(Address(a1, SoftwarePrefetchHintDistance));
+ __ prfm(Address(a2, SoftwarePrefetchHintDistance));
+ }
+ __ ldp(tmp5, tmp7, Address(__ post(a1, 2 * wordSize)));
+ __ eor(tmp1, tmp1, tmp2);
+ __ eor(tmp3, tmp3, tmp4);
+ __ ldp(tmp6, tmp8, Address(__ post(a2, 2 * wordSize)));
+ __ orr(tmp1, tmp1, tmp3);
+ __ cbnz(tmp1, NOT_EQUAL);
+ __ ldp(tmp1, tmp3, Address(__ post(a1, 2 * wordSize)));
+ __ eor(tmp5, tmp5, tmp6);
+ __ eor(tmp7, tmp7, tmp8);
+ __ ldp(tmp2, tmp4, Address(__ post(a2, 2 * wordSize)));
+ __ orr(tmp5, tmp5, tmp7);
+ __ cbnz(tmp5, NOT_EQUAL);
+ __ ldp(tmp5, tmp7, Address(__ post(a1, 2 * wordSize)));
+ __ eor(tmp1, tmp1, tmp2);
+ __ eor(tmp3, tmp3, tmp4);
+ __ ldp(tmp6, tmp8, Address(__ post(a2, 2 * wordSize)));
+ __ orr(tmp1, tmp1, tmp3);
+ __ cbnz(tmp1, NOT_EQUAL);
+ __ ldp(tmp1, tmp3, Address(__ post(a1, 2 * wordSize)));
+ __ eor(tmp5, tmp5, tmp6);
+ __ sub(cnt1, cnt1, 8 * wordSize);
+ __ eor(tmp7, tmp7, tmp8);
+ __ ldp(tmp2, tmp4, Address(__ post(a2, 2 * wordSize)));
+ __ cmp(cnt1, loopThreshold);
+ __ orr(tmp5, tmp5, tmp7);
+ __ cbnz(tmp5, NOT_EQUAL);
+ __ br(__ GE, LOOP);
+ // post-loop
+ __ eor(tmp1, tmp1, tmp2);
+ __ eor(tmp3, tmp3, tmp4);
+ __ orr(tmp1, tmp1, tmp3);
+ __ sub(cnt1, cnt1, 2 * wordSize);
+ __ cbnz(tmp1, NOT_EQUAL);
+ }
+
+ void generate_large_array_equals_loop_simd(int loopThreshold,
+ bool usePrefetch, Label &NOT_EQUAL) {
+ Register a1 = r1, a2 = r2, result = r0, cnt1 = r10, tmp1 = rscratch1,
+ tmp2 = rscratch2;
+ Label LOOP;
+
+ __ bind(LOOP);
+ if (usePrefetch) {
+ __ prfm(Address(a1, SoftwarePrefetchHintDistance));
+ __ prfm(Address(a2, SoftwarePrefetchHintDistance));
+ }
+ __ ld1(v0, v1, v2, v3, __ T2D, Address(__ post(a1, 4 * 2 * wordSize)));
+ __ sub(cnt1, cnt1, 8 * wordSize);
+ __ ld1(v4, v5, v6, v7, __ T2D, Address(__ post(a2, 4 * 2 * wordSize)));
+ __ cmp(cnt1, loopThreshold);
+ __ eor(v0, __ T16B, v0, v4);
+ __ eor(v1, __ T16B, v1, v5);
+ __ eor(v2, __ T16B, v2, v6);
+ __ eor(v3, __ T16B, v3, v7);
+ __ orr(v0, __ T16B, v0, v1);
+ __ orr(v1, __ T16B, v2, v3);
+ __ orr(v0, __ T16B, v0, v1);
+ __ umov(tmp1, v0, __ D, 0);
+ __ umov(tmp2, v0, __ D, 1);
+ __ orr(tmp1, tmp1, tmp2);
+ __ cbnz(tmp1, NOT_EQUAL);
+ __ br(__ GE, LOOP);
+ }
+
+ // a1 = r1 - array1 address
+ // a2 = r2 - array2 address
+ // result = r0 - return value. Already contains "false"
+ // cnt1 = r10 - amount of elements left to check, reduced by wordSize
+ // r3-r5 are reserved temporary registers
+ address generate_large_array_equals() {
+ StubCodeMark mark(this, "StubRoutines", "large_array_equals");
+ Register a1 = r1, a2 = r2, result = r0, cnt1 = r10, tmp1 = rscratch1,
+ tmp2 = rscratch2, tmp3 = r3, tmp4 = r4, tmp5 = r5, tmp6 = r11,
+ tmp7 = r12, tmp8 = r13;
+ Label TAIL, NOT_EQUAL, EQUAL, NOT_EQUAL_NO_POP, NO_PREFETCH_LARGE_LOOP,
+ SMALL_LOOP, POST_LOOP;
+ const int PRE_LOOP_SIZE = UseSIMDForArrayEquals ? 0 : 16;
+ // calculate if at least 32 prefetched bytes are used
+ int prefetchLoopThreshold = SoftwarePrefetchHintDistance + 32;
+ int nonPrefetchLoopThreshold = (64 + PRE_LOOP_SIZE);
+ RegSet spilled_regs = RegSet::range(tmp6, tmp8);
+ assert_different_registers(a1, a2, result, cnt1, tmp1, tmp2, tmp3, tmp4,
+ tmp5, tmp6, tmp7, tmp8);
+
+ __ align(CodeEntryAlignment);
+ address entry = __ pc();
+ __ enter();
+ __ sub(cnt1, cnt1, wordSize); // first 8 bytes were loaded outside of stub
+ // also advance pointers to use post-increment instead of pre-increment
+ __ add(a1, a1, wordSize);
+ __ add(a2, a2, wordSize);
+ if (AvoidUnalignedAccesses) {
+ // both implementations (SIMD/nonSIMD) are using relatively large load
+ // instructions (ld1/ldp), which has huge penalty (up to x2 exec time)
+ // on some CPUs in case of address is not at least 16-byte aligned.
+ // Arrays are 8-byte aligned currently, so, we can make additional 8-byte
+ // load if needed at least for 1st address and make if 16-byte aligned.
+ Label ALIGNED16;
+ __ tbz(a1, 3, ALIGNED16);
+ __ ldr(tmp1, Address(__ post(a1, wordSize)));
+ __ ldr(tmp2, Address(__ post(a2, wordSize)));
+ __ sub(cnt1, cnt1, wordSize);
+ __ eor(tmp1, tmp1, tmp2);
+ __ cbnz(tmp1, NOT_EQUAL_NO_POP);
+ __ bind(ALIGNED16);
+ }
+ if (UseSIMDForArrayEquals) {
+ if (SoftwarePrefetchHintDistance >= 0) {
+ __ cmp(cnt1, prefetchLoopThreshold);
+ __ br(__ LE, NO_PREFETCH_LARGE_LOOP);
+ generate_large_array_equals_loop_simd(prefetchLoopThreshold,
+ /* prfm = */ true, NOT_EQUAL);
+ __ cmp(cnt1, nonPrefetchLoopThreshold);
+ __ br(__ LT, TAIL);
+ }
+ __ bind(NO_PREFETCH_LARGE_LOOP);
+ generate_large_array_equals_loop_simd(nonPrefetchLoopThreshold,
+ /* prfm = */ false, NOT_EQUAL);
+ } else {
+ __ push(spilled_regs, sp);
+ if (SoftwarePrefetchHintDistance >= 0) {
+ __ cmp(cnt1, prefetchLoopThreshold);
+ __ br(__ LE, NO_PREFETCH_LARGE_LOOP);
+ generate_large_array_equals_loop_nonsimd(prefetchLoopThreshold,
+ /* prfm = */ true, NOT_EQUAL);
+ __ cmp(cnt1, nonPrefetchLoopThreshold);
+ __ br(__ LT, TAIL);
+ }
+ __ bind(NO_PREFETCH_LARGE_LOOP);
+ generate_large_array_equals_loop_nonsimd(nonPrefetchLoopThreshold,
+ /* prfm = */ false, NOT_EQUAL);
+ }
+ __ bind(TAIL);
+ __ cbz(cnt1, EQUAL);
+ __ subs(cnt1, cnt1, wordSize);
+ __ br(__ LE, POST_LOOP);
+ __ bind(SMALL_LOOP);
+ __ ldr(tmp1, Address(__ post(a1, wordSize)));
+ __ ldr(tmp2, Address(__ post(a2, wordSize)));
+ __ subs(cnt1, cnt1, wordSize);
+ __ eor(tmp1, tmp1, tmp2);
+ __ cbnz(tmp1, NOT_EQUAL);
+ __ br(__ GT, SMALL_LOOP);
+ __ bind(POST_LOOP);
+ __ ldr(tmp1, Address(a1, cnt1));
+ __ ldr(tmp2, Address(a2, cnt1));
+ __ eor(tmp1, tmp1, tmp2);
+ __ cbnz(tmp1, NOT_EQUAL);
+ __ bind(EQUAL);
+ __ mov(result, true);
+ __ bind(NOT_EQUAL);
+ if (!UseSIMDForArrayEquals) {
+ __ pop(spilled_regs, sp);
+ }
+ __ bind(NOT_EQUAL_NO_POP);
+ __ leave();
+ __ ret(lr);
+ return entry;
+ }
+
+
/**
* Arguments:
*
@@ -4895,6 +5071,11 @@
// has negatives stub for large arrays.
StubRoutines::aarch64::_has_negatives = generate_has_negatives(StubRoutines::aarch64::_has_negatives_long);
+ // array equals stub for large arrays.
+ if (!UseSimpleArrayEquals) {
+ StubRoutines::aarch64::_large_array_equals = generate_large_array_equals();
+ }
+
if (UseMultiplyToLenIntrinsic) {
StubRoutines::_multiplyToLen = generate_multiplyToLen();
}
--- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -46,6 +46,7 @@
address StubRoutines::aarch64::_zero_blocks = NULL;
address StubRoutines::aarch64::_has_negatives = NULL;
address StubRoutines::aarch64::_has_negatives_long = NULL;
+address StubRoutines::aarch64::_large_array_equals = NULL;
bool StubRoutines::aarch64::_completed = false;
/**
--- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -65,6 +65,7 @@
static address _has_negatives;
static address _has_negatives_long;
+ static address _large_array_equals;
static bool _completed;
public:
@@ -131,6 +132,10 @@
return _has_negatives_long;
}
+ static address large_array_equals() {
+ return _large_array_equals;
+ }
+
static bool complete() {
return _completed;
}
--- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, 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.
*
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
@@ -889,7 +890,6 @@
// Method entry for java.lang.ref.Reference.get.
address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
-#if INCLUDE_ALL_GCS
// Code: _aload_0, _getfield, _areturn
// parameter size = 1
//
@@ -923,43 +923,29 @@
const int referent_offset = java_lang_ref_Reference::referent_offset;
guarantee(referent_offset > 0, "referent offset not initialized");
- if (UseG1GC) {
- Label slow_path;
- const Register local_0 = c_rarg0;
- // Check if local 0 != NULL
- // If the receiver is null then it is OK to jump to the slow path.
- __ ldr(local_0, Address(esp, 0));
- __ cbz(local_0, slow_path);
+ Label slow_path;
+ const Register local_0 = c_rarg0;
+ // Check if local 0 != NULL
+ // If the receiver is null then it is OK to jump to the slow path.
+ __ ldr(local_0, Address(esp, 0));
+ __ cbz(local_0, slow_path);
- // Load the value of the referent field.
- const Address field_address(local_0, referent_offset);
- __ load_heap_oop(local_0, field_address);
+ __ mov(r19, r13); // Move senderSP to a callee-saved register
- __ mov(r19, r13); // Move senderSP to a callee-saved register
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer.
- __ enter(); // g1_write may call runtime
- __ g1_write_barrier_pre(noreg /* obj */,
- local_0 /* pre_val */,
- rthread /* thread */,
- rscratch2 /* tmp */,
- true /* tosca_live */,
- true /* expand_call */);
- __ leave();
- // areturn
- __ andr(sp, r19, -16); // done with stack
- __ ret(lr);
+ // Load the value of the referent field.
+ const Address field_address(local_0, referent_offset);
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->load_at(_masm, IN_HEAP | ON_WEAK_OOP_REF, T_OBJECT, local_0, field_address, /*tmp1*/ rscratch2, /*tmp2*/ rscratch1);
- // generate a vanilla interpreter entry as the slow path
- __ bind(slow_path);
- __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
- return entry;
- }
-#endif // INCLUDE_ALL_GCS
+ // areturn
+ __ andr(sp, r19, -16); // done with stack
+ __ ret(lr);
- // If G1 is not enabled then attempt to go through the accessor entry point
- // Reference.get is an accessor
- return NULL;
+ // generate a vanilla interpreter entry as the slow path
+ __ bind(slow_path);
+ __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
+ return entry;
+
}
/**
@@ -1434,28 +1420,7 @@
__ br(Assembler::NE, no_oop);
// Unbox oop result, e.g. JNIHandles::resolve result.
__ pop(ltos);
- __ cbz(r0, store_result); // Use NULL as-is.
- STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u);
- __ tbz(r0, 0, not_weak); // Test for jweak tag.
- // Resolve jweak.
- __ ldr(r0, Address(r0, -JNIHandles::weak_tag_value));
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- __ enter(); // Barrier may call runtime.
- __ g1_write_barrier_pre(noreg /* obj */,
- r0 /* pre_val */,
- rthread /* thread */,
- t /* tmp */,
- true /* tosca_live */,
- true /* expand_call */);
- __ leave();
- }
-#endif // INCLUDE_ALL_GCS
- __ b(store_result);
- __ bind(not_weak);
- // Resolve (untagged) jobject.
- __ ldr(r0, Address(r0, 0));
- __ bind(store_result);
+ __ resolve_jobject(r0, rthread, t);
__ str(r0, Address(rfp, frame::interpreter_frame_oop_temp_offset*wordSize));
// keep stack depth as expected by pushing oop which will eventually be discarded
__ push(ltos);
--- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/interp_masm.hpp"
@@ -142,76 +143,20 @@
// Store an oop (or NULL) at the Address described by obj.
// If val == noreg this means store a NULL
static void do_oop_store(InterpreterMacroAssembler* _masm,
- Address obj,
+ Address dst,
Register val,
- BarrierSet::Name barrier,
- bool precise) {
+ DecoratorSet decorators) {
assert(val == noreg || val == r0, "parameter is just for looks");
- switch (barrier) {
-#if INCLUDE_ALL_GCS
- case BarrierSet::G1BarrierSet:
- {
- // flatten object address if needed
- if (obj.index() == noreg && obj.offset() == 0) {
- if (obj.base() != r3) {
- __ mov(r3, obj.base());
- }
- } else {
- __ lea(r3, obj);
- }
- __ g1_write_barrier_pre(r3 /* obj */,
- r1 /* pre_val */,
- rthread /* thread */,
- r10 /* tmp */,
- val != noreg /* tosca_live */,
- false /* expand_call */);
- if (val == noreg) {
- __ store_heap_oop_null(Address(r3, 0));
- } else {
- // G1 barrier needs uncompressed oop for region cross check.
- Register new_val = val;
- if (UseCompressedOops) {
- new_val = rscratch2;
- __ mov(new_val, val);
- }
- __ store_heap_oop(Address(r3, 0), val);
- __ g1_write_barrier_post(r3 /* store_adr */,
- new_val /* new_val */,
- rthread /* thread */,
- r10 /* tmp */,
- r1 /* tmp2 */);
- }
-
- }
- break;
-#endif // INCLUDE_ALL_GCS
- case BarrierSet::CardTableBarrierSet:
- {
- if (val == noreg) {
- __ store_heap_oop_null(obj);
- } else {
- __ store_heap_oop(obj, val);
- // flatten object address if needed
- if (!precise || (obj.index() == noreg && obj.offset() == 0)) {
- __ store_check(obj.base());
- } else {
- __ lea(r3, obj);
- __ store_check(r3);
- }
- }
- }
- break;
- case BarrierSet::ModRef:
- if (val == noreg) {
- __ store_heap_oop_null(obj);
- } else {
- __ store_heap_oop(obj, val);
- }
- break;
- default :
- ShouldNotReachHere();
-
- }
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->store_at(_masm, decorators, T_OBJECT, dst, val, /*tmp1*/ r10, /*tmp2*/ r1);
+}
+
+static void do_oop_load(InterpreterMacroAssembler* _masm,
+ Address src,
+ Register dst,
+ DecoratorSet decorators) {
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->load_at(_masm, decorators, T_OBJECT, dst, src, /*tmp1*/ r10, /*tmp_thread*/ r1);
}
Address TemplateTable::at_bcp(int offset) {
@@ -865,7 +810,10 @@
index_check(r0, r1); // leaves index in r1, kills rscratch1
int s = (UseCompressedOops ? 2 : 3);
__ lea(r1, Address(r0, r1, Address::uxtw(s)));
- __ load_heap_oop(r0, Address(r1, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
+ do_oop_load(_masm,
+ Address(r1, arrayOopDesc::base_offset_in_bytes(T_OBJECT)),
+ r0,
+ IN_HEAP | IN_HEAP_ARRAY);
}
void TemplateTable::baload()
@@ -1193,7 +1141,7 @@
// Get the value we will store
__ ldr(r0, at_tos());
// Now store using the appropriate barrier
- do_oop_store(_masm, element_address, r0, _bs->kind(), true);
+ do_oop_store(_masm, element_address, r0, IN_HEAP | IN_HEAP_ARRAY);
__ b(done);
// Have a NULL in r0, r3=array, r2=index. Store NULL at ary[idx]
@@ -1201,7 +1149,7 @@
__ profile_null_seen(r2);
// Store a NULL
- do_oop_store(_masm, element_address, noreg, _bs->kind(), true);
+ do_oop_store(_masm, element_address, noreg, IN_HEAP | IN_HEAP_ARRAY);
// Pop stack arguments
__ bind(done);
@@ -2591,7 +2539,7 @@
__ cmp(flags, atos);
__ br(Assembler::NE, notObj);
// atos
- __ load_heap_oop(r0, field);
+ do_oop_load(_masm, field, r0, IN_HEAP);
__ push(atos);
if (rc == may_rewrite) {
patch_bytecode(Bytecodes::_fast_agetfield, bc, r1);
@@ -2834,7 +2782,7 @@
__ pop(atos);
if (!is_static) pop_and_check_object(obj);
// Store into the field
- do_oop_store(_masm, field, r0, _bs->kind(), false);
+ do_oop_store(_masm, field, r0, IN_HEAP);
if (rc == may_rewrite) {
patch_bytecode(Bytecodes::_fast_aputfield, bc, r1, true, byte_no);
}
@@ -3054,7 +3002,7 @@
// access field
switch (bytecode()) {
case Bytecodes::_fast_aputfield:
- do_oop_store(_masm, field, r0, _bs->kind(), false);
+ do_oop_store(_masm, field, r0, IN_HEAP);
break;
case Bytecodes::_fast_lputfield:
__ str(r0, field);
@@ -3146,7 +3094,7 @@
// access field
switch (bytecode()) {
case Bytecodes::_fast_agetfield:
- __ load_heap_oop(r0, field);
+ do_oop_load(_masm, field, r0, IN_HEAP);
__ verify_oop(r0);
break;
case Bytecodes::_fast_lgetfield:
@@ -3216,7 +3164,7 @@
__ ldrw(r0, Address(r0, r1, Address::lsl(0)));
break;
case atos:
- __ load_heap_oop(r0, Address(r0, r1, Address::lsl(0)));
+ do_oop_load(_masm, Address(r0, r1, Address::lsl(0)), r0, IN_HEAP);
__ verify_oop(r0);
break;
case ftos:
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -203,7 +203,11 @@
if (FLAG_IS_DEFAULT(UseSIMDForMemoryOps)) {
FLAG_SET_DEFAULT(UseSIMDForMemoryOps, (_variant > 0));
}
+ if (FLAG_IS_DEFAULT(UseSIMDForArrayEquals)) {
+ FLAG_SET_DEFAULT(UseSIMDForArrayEquals, false);
+ }
}
+
// ThunderX2
if ((_cpu == CPU_CAVIUM && (_model == 0xAF)) ||
(_cpu == CPU_BROADCOM && (_model == 0x516))) {
@@ -218,7 +222,25 @@
}
}
- if (_cpu == CPU_ARM && (_model == 0xd03 || _model2 == 0xd03)) _features |= CPU_A53MAC;
+ // Cortex A53
+ if (_cpu == CPU_ARM && (_model == 0xd03 || _model2 == 0xd03)) {
+ _features |= CPU_A53MAC;
+ if (FLAG_IS_DEFAULT(UseSIMDForArrayEquals)) {
+ FLAG_SET_DEFAULT(UseSIMDForArrayEquals, false);
+ }
+ }
+
+ // Cortex A73
+ if (_cpu == CPU_ARM && (_model == 0xd09 || _model2 == 0xd09)) {
+ if (FLAG_IS_DEFAULT(SoftwarePrefetchHintDistance)) {
+ FLAG_SET_DEFAULT(SoftwarePrefetchHintDistance, -1);
+ }
+ // A73 is faster with short-and-easy-for-speculative-execution-loop
+ if (FLAG_IS_DEFAULT(UseSimpleArrayEquals)) {
+ FLAG_SET_DEFAULT(UseSimpleArrayEquals, true);
+ }
+ }
+
if (_cpu == CPU_ARM && (_model == 0xd07 || _model2 == 0xd07)) _features |= CPU_STXR_PREFETCH;
// If an olde style /proc/cpuinfo (cpu_lines == 1) then if _model is an A57 (0xd07)
// we assume the worst and assume we could be on a big little system and have
--- a/src/hotspot/cpu/arm/assembler_arm.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/arm/assembler_arm.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,7 +44,6 @@
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/heapRegion.hpp"
#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/cpu/arm/assembler_arm_32.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/arm/assembler_arm_32.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,7 +44,6 @@
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/heapRegion.hpp"
#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/cpu/arm/assembler_arm_64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/arm/assembler_arm_64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,7 +44,6 @@
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/heapRegion.hpp"
#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -533,9 +533,11 @@
set_card(tmp, card_addr);
__ branch_destination(L_already_dirty->label());
} else {
+#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
__ membar_storestore();
}
+#endif
set_card(tmp, card_addr);
}
}
--- a/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/arm/c1_Runtime1_arm.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -45,6 +45,7 @@
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#endif
// Note: Rtemp usage is this file should not impact C2 and should be
@@ -540,7 +541,7 @@
__ set_info("g1_pre_barrier_slow_id", dont_gc_arguments);
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ mov(R0, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0);
@@ -564,12 +565,9 @@
const Register r_index_1 = R1;
const Register r_buffer_2 = R2;
- Address queue_active(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active()));
- Address queue_index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_index()));
- Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf()));
+ Address queue_active(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+ Address queue_index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
+ Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
Label done;
Label runtime;
@@ -620,7 +618,7 @@
__ set_info("g1_post_barrier_slow_id", dont_gc_arguments);
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ mov(R0, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), R0);
@@ -632,10 +630,8 @@
Label recheck;
Label runtime;
- Address queue_index(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_index()));
- Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf()));
+ Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
+ Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
AddressLiteral cardtable(ci_card_table_address_as<address>(), relocInfo::none);
--- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,7 +28,6 @@
#include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/heapRegion.hpp"
-#include "gc/shared/collectedHeap.hpp"
#include "interpreter/interp_masm.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/thread.hpp"
--- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -35,6 +35,8 @@
Register addr, Register count, int callee_saved_regs) {}
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register addr, Register count, Register tmp) {}
+
+ virtual void barrier_stubs_init() {}
};
#endif // CPU_ARM_GC_SHARED_BARRIERSETASSEMBLER_ARM_HPP
--- a/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,7 +44,7 @@
void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register tmp) {
BLOCK_COMMENT("CardTablePostBarrier");
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
--- a/src/hotspot/cpu/arm/interp_masm_arm.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -45,7 +45,6 @@
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/heapRegion.hpp"
#endif // INCLUDE_ALL_GCS
@@ -411,7 +410,7 @@
// Sets card_table_base register.
void InterpreterMacroAssembler::store_check_part1(Register card_table_base) {
// Check barrier set type (should be card table) and element size
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
assert(bs->kind() == BarrierSet::CardTableBarrierSet,
"Wrong barrier set kind");
@@ -451,9 +450,11 @@
#endif
if (UseCondCardMark) {
+#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC) {
membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), noreg);
}
+#endif
Label already_dirty;
ldrb(tmp, card_table_addr);
@@ -463,9 +464,11 @@
bind(already_dirty);
} else {
+#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore), noreg);
}
+#endif
set_card(card_table_base, card_table_addr, tmp);
}
}
@@ -474,7 +477,7 @@
#ifdef AARCH64
strb(ZR, card_table_addr);
#else
- CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(Universe::heap()->barrier_set());
+ CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
CardTable* ct = ctbs->card_table();
if ((((uintptr_t)ct->byte_map_base() & 0xff) == 0)) {
// Card table is aligned so the lowest byte of the table address base is zero.
--- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -29,6 +29,7 @@
#include "ci/ciEnv.hpp"
#include "code/nativeInst.hpp"
#include "compiler/disassembler.hpp"
+#include "gc/shared/barrierSet.hpp"
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
@@ -46,7 +47,7 @@
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
#endif
@@ -2175,12 +2176,9 @@
assert_different_registers(pre_val, tmp1, tmp2, noreg);
}
- Address in_progress(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active()));
- Address index(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_index()));
- Address buffer(Rthread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf()));
+ Address in_progress(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+ Address index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
+ Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
// Is marking active?
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code");
@@ -2261,12 +2259,10 @@
Register tmp2,
Register tmp3) {
- Address queue_index(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_index()));
- Address buffer(Rthread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf()));
-
- BarrierSet* bs = Universe::heap()->barrier_set();
+ Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
+ Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
+
+ BarrierSet* bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
Label done;
--- a/src/hotspot/cpu/ppc/assembler_ppc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/assembler_ppc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -39,7 +39,6 @@
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/heapRegion.hpp"
#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -620,7 +620,7 @@
inline void Assembler::stqcx_(Register s, Register a, Register b) { emit_int32( STQCX_OPCODE | rs(s) | ra0mem(a) | rb(b) | rc(1)); }
// Instructions for adjusting thread priority
-// for simultaneous multithreading (SMT) on POWER5.
+// for simultaneous multithreading (SMT) on >= POWER5.
inline void Assembler::smt_prio_very_low() { Assembler::or_unchecked(R31, R31, R31); }
inline void Assembler::smt_prio_low() { Assembler::or_unchecked(R1, R1, R1); }
inline void Assembler::smt_prio_medium_low() { Assembler::or_unchecked(R6, R6, R6); }
@@ -628,11 +628,11 @@
inline void Assembler::smt_prio_medium_high() { Assembler::or_unchecked(R5, R5, R5); }
inline void Assembler::smt_prio_high() { Assembler::or_unchecked(R3, R3, R3); }
// >= Power7
-inline void Assembler::smt_yield() { Assembler::or_unchecked(R27, R27, R27); }
-inline void Assembler::smt_mdoio() { Assembler::or_unchecked(R29, R29, R29); }
-inline void Assembler::smt_mdoom() { Assembler::or_unchecked(R30, R30, R30); }
-// >= Power8
-inline void Assembler::smt_miso() { Assembler::or_unchecked(R26, R26, R26); }
+inline void Assembler::smt_yield() { Assembler::or_unchecked(R27, R27, R27); } // never actually implemented
+inline void Assembler::smt_mdoio() { Assembler::or_unchecked(R29, R29, R29); } // never actually implemetned
+inline void Assembler::smt_mdoom() { Assembler::or_unchecked(R30, R30, R30); } // never actually implemented
+// Power8
+inline void Assembler::smt_miso() { Assembler::or_unchecked(R26, R26, R26); } // never actually implemented
inline void Assembler::twi_0(Register a) { twi_unchecked(0, a, 0);}
--- a/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/c1_Runtime1_ppc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -45,6 +45,7 @@
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#endif
// Implementation of StubAssembler
@@ -710,7 +711,7 @@
#if INCLUDE_ALL_GCS
case g1_pre_barrier_slow_id:
{
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
goto unimplemented_entry;
}
@@ -724,15 +725,9 @@
Register tmp2 = R15;
Label refill, restart, marking_not_active;
- int satb_q_active_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active());
- int satb_q_index_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_index());
- int satb_q_buf_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf());
+ int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
+ int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
+ int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
// Spill
__ std(tmp, -16, R1_SP);
@@ -787,7 +782,7 @@
case g1_post_barrier_slow_id:
{
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
goto unimplemented_entry;
}
@@ -829,12 +824,8 @@
__ li(tmp, G1CardTable::dirty_card_val());
__ stb(tmp, 0, addr);
- int dirty_card_q_index_byte_offset =
- in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_index());
- int dirty_card_q_buf_byte_offset =
- in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf());
+ int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
+ int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
__ bind(restart);
--- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,10 +28,10 @@
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1BarrierSetAssembler.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
-#include "gc/shared/collectedHeap.hpp"
-#include "runtime/thread.hpp"
#include "interpreter/interp_masm.hpp"
+#include "runtime/sharedRuntime.hpp"
#define __ masm->
@@ -49,10 +49,10 @@
// Is marking active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ lwz(R0, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread);
+ __ lwz(R0, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread);
} else {
guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- __ lbz(R0, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread);
+ __ lbz(R0, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread);
}
__ cmpdi(CCR0, R0, 0);
__ beq(CCR0, filtered);
@@ -98,3 +98,245 @@
__ addi(R1_SP, R1_SP, frame_size); // pop_frame();
__ restore_LR_CR(R0);
}
+
+void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, DecoratorSet decorators, Register obj, RegisterOrConstant ind_or_offs, Register pre_val,
+ Register tmp1, Register tmp2, bool needs_frame) {
+ bool not_null = (decorators & OOP_NOT_NULL) != 0,
+ preloaded = obj == noreg;
+ Register nv_save = noreg;
+
+ if (preloaded) {
+ // We are not loading the previous value so make
+ // sure that we don't trash the value in pre_val
+ // with the code below.
+ assert_different_registers(pre_val, tmp1, tmp2);
+ if (pre_val->is_volatile()) {
+ nv_save = !tmp1->is_volatile() ? tmp1 : tmp2;
+ assert(!nv_save->is_volatile(), "need one nv temp register if pre_val lives in volatile register");
+ }
+ }
+
+ Label runtime, filtered;
+
+ // Is marking active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ lwz(tmp1, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread);
+ } else {
+ guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ lbz(tmp1, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread);
+ }
+ __ cmpdi(CCR0, tmp1, 0);
+ __ beq(CCR0, filtered);
+
+ // Do we need to load the previous value?
+ if (!preloaded) {
+ // Load the previous value...
+ if (UseCompressedOops) {
+ __ lwz(pre_val, ind_or_offs, obj);
+ } else {
+ __ ld(pre_val, ind_or_offs, obj);
+ }
+ // Previous value has been loaded into Rpre_val.
+ }
+ assert(pre_val != noreg, "must have a real register");
+
+ // Is the previous value null?
+ if (preloaded && not_null) {
+#ifdef ASSERT
+ __ cmpdi(CCR0, pre_val, 0);
+ __ asm_assert_ne("null oop not allowed (G1 pre)", 0x321); // Checked by caller.
+#endif
+ } else {
+ __ cmpdi(CCR0, pre_val, 0);
+ __ beq(CCR0, filtered);
+ }
+
+ if (!preloaded && UseCompressedOops) {
+ __ decode_heap_oop_not_null(pre_val);
+ }
+
+ // OK, it's not filtered, so we'll need to call enqueue. In the normal
+ // case, pre_val will be a scratch G-reg, but there are some cases in
+ // which it's an O-reg. In the first case, do a normal call. In the
+ // latter, do a save here and call the frameless version.
+
+ // Can we store original value in the thread's buffer?
+ // Is index == 0?
+ // (The index field is typed as size_t.)
+ const Register Rbuffer = tmp1, Rindex = tmp2;
+
+ __ ld(Rindex, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()), R16_thread);
+ __ cmpdi(CCR0, Rindex, 0);
+ __ beq(CCR0, runtime); // If index == 0, goto runtime.
+ __ ld(Rbuffer, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()), R16_thread);
+
+ __ addi(Rindex, Rindex, -wordSize); // Decrement index.
+ __ std(Rindex, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()), R16_thread);
+
+ // Record the previous value.
+ __ stdx(pre_val, Rbuffer, Rindex);
+ __ b(filtered);
+
+ __ bind(runtime);
+
+ // May need to preserve LR. Also needed if current frame is not compatible with C calling convention.
+ if (needs_frame) {
+ __ save_LR_CR(tmp1);
+ __ push_frame_reg_args(0, tmp2);
+ }
+
+ if (pre_val->is_volatile() && preloaded) { __ mr(nv_save, pre_val); } // Save pre_val across C call if it was preloaded.
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, R16_thread);
+ if (pre_val->is_volatile() && preloaded) { __ mr(pre_val, nv_save); } // restore
+
+ if (needs_frame) {
+ __ pop_frame();
+ __ restore_LR_CR(tmp1);
+ }
+
+ __ bind(filtered);
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators, Register store_addr, Register new_val,
+ Register tmp1, Register tmp2, Register tmp3) {
+ bool not_null = (decorators & OOP_NOT_NULL) != 0;
+
+ Label runtime, filtered;
+ assert_different_registers(store_addr, new_val, tmp1, tmp2);
+
+ CardTableBarrierSet* ct = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
+ assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code");
+
+ // Does store cross heap regions?
+ if (G1RSBarrierRegionFilter) {
+ __ xorr(tmp1, store_addr, new_val);
+ __ srdi_(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes);
+ __ beq(CCR0, filtered);
+ }
+
+ // Crosses regions, storing NULL?
+ if (not_null) {
+#ifdef ASSERT
+ __ cmpdi(CCR0, new_val, 0);
+ __ asm_assert_ne("null oop not allowed (G1 post)", 0x322); // Checked by caller.
+#endif
+ } else {
+ __ cmpdi(CCR0, new_val, 0);
+ __ beq(CCR0, filtered);
+ }
+
+ // Storing region crossing non-NULL, is card already dirty?
+ const Register Rcard_addr = tmp1;
+ Register Rbase = tmp2;
+ __ load_const_optimized(Rbase, (address)(ct->card_table()->byte_map_base()), /*temp*/ tmp3);
+
+ __ srdi(Rcard_addr, store_addr, CardTable::card_shift);
+
+ // Get the address of the card.
+ __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr);
+ __ cmpwi(CCR0, tmp3, (int)G1CardTable::g1_young_card_val());
+ __ beq(CCR0, filtered);
+
+ __ membar(Assembler::StoreLoad);
+ __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr); // Reload after membar.
+ __ cmpwi(CCR0, tmp3 /* card value */, (int)G1CardTable::dirty_card_val());
+ __ beq(CCR0, filtered);
+
+ // Storing a region crossing, non-NULL oop, card is clean.
+ // Dirty card and log.
+ __ li(tmp3, (int)G1CardTable::dirty_card_val());
+ //release(); // G1: oops are allowed to get visible after dirty marking.
+ __ stbx(tmp3, Rbase, Rcard_addr);
+
+ __ add(Rcard_addr, Rbase, Rcard_addr); // This is the address which needs to get enqueued.
+ Rbase = noreg; // end of lifetime
+
+ const Register Rqueue_index = tmp2,
+ Rqueue_buf = tmp3;
+ __ ld(Rqueue_index, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()), R16_thread);
+ __ cmpdi(CCR0, Rqueue_index, 0);
+ __ beq(CCR0, runtime); // index == 0 then jump to runtime
+ __ ld(Rqueue_buf, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()), R16_thread);
+
+ __ addi(Rqueue_index, Rqueue_index, -wordSize); // decrement index
+ __ std(Rqueue_index, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()), R16_thread);
+
+ __ stdx(Rcard_addr, Rqueue_buf, Rqueue_index); // store card
+ __ b(filtered);
+
+ __ bind(runtime);
+
+ // Save the live input values.
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), Rcard_addr, R16_thread);
+
+ __ bind(filtered);
+}
+
+void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
+ bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
+ bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
+ bool precise = on_array || on_anonymous;
+ // Load and record the previous value.
+ g1_write_barrier_pre(masm, decorators, base, ind_or_offs,
+ tmp1, tmp2, tmp3, needs_frame);
+
+ BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, needs_frame);
+
+ // No need for post barrier if storing NULL
+ if (val != noreg) {
+ if (precise) {
+ if (ind_or_offs.is_constant()) {
+ __ add_const_optimized(base, base, ind_or_offs.as_constant(), tmp1);
+ } else {
+ __ add(base, ind_or_offs.as_register(), base);
+ }
+ }
+ g1_write_barrier_post(masm, decorators, base, val, tmp1, tmp2, tmp3);
+ }
+}
+
+void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register dst,
+ Register tmp1, Register tmp2, bool needs_frame, Label *is_null) {
+ bool on_oop = type == T_OBJECT || type == T_ARRAY;
+ bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
+ bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
+ bool on_reference = on_weak || on_phantom;
+ Label done;
+ if (on_oop && on_reference && is_null == NULL) { is_null = &done; }
+ // Load the value of the referent field.
+ ModRefBarrierSetAssembler::load_at(masm, decorators, type, base, ind_or_offs, dst, tmp1, tmp2, needs_frame, is_null);
+ if (on_oop && on_reference) {
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer. Note with
+ // these parameters the pre-barrier does not generate
+ // the load of the previous value
+ // We only reach here if value is not null.
+ g1_write_barrier_pre(masm, decorators | OOP_NOT_NULL, noreg /* obj */, (intptr_t)0, dst /* pre_val */,
+ tmp1, tmp2, needs_frame);
+ }
+ __ bind(done);
+}
+
+void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2, bool needs_frame) {
+ Label done, not_weak;
+ __ cmpdi(CCR0, value, 0);
+ __ beq(CCR0, done); // Use NULL as-is.
+
+ __ clrrdi(tmp1, value, JNIHandles::weak_tag_size);
+ __ andi_(tmp2, value, JNIHandles::weak_tag_mask);
+ __ ld(value, 0, tmp1); // Resolve (untagged) jobject.
+
+ __ beq(CCR0, not_weak); // Test for jweak tag.
+ __ verify_oop(value);
+ g1_write_barrier_pre(masm, IN_ROOT | ON_PHANTOM_OOP_REF,
+ noreg, noreg, value,
+ tmp1, tmp2, needs_frame);
+ __ bind(not_weak);
+ __ verify_oop(value);
+ __ bind(done);
+}
+
+#undef __
--- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -34,6 +34,22 @@
virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register from, Register to, Register count,
Register preserve1, Register preserve2);
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register preserve);
+
+ void g1_write_barrier_pre(MacroAssembler* masm, DecoratorSet decorators, Register obj, RegisterOrConstant ind_or_offs, Register pre_val,
+ Register tmp1, Register tmp2, bool needs_frame);
+ void g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators, Register store_addr, Register new_val,
+ Register tmp1, Register tmp2, Register tmp3);
+
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame);
+
+public:
+ virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register dst,
+ Register tmp1, Register tmp2, bool needs_frame, Label *is_null = NULL);
+
+ virtual void resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2, bool needs_frame);
};
#endif // CPU_PPC_GC_G1_G1BARRIERSETASSEMBLER_PPC_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, SAP SE. All rights reserved.
+ * 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 "asm/macroAssembler.inline.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
+#include "interpreter/interp_masm.hpp"
+
+#define __ masm->
+
+void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
+ bool on_heap = (decorators & IN_HEAP) != 0;
+ bool on_root = (decorators & IN_ROOT) != 0;
+ bool not_null = (decorators & OOP_NOT_NULL) != 0;
+ assert(on_heap || on_root, "where?");
+ assert_different_registers(base, val, tmp1, tmp2, R0);
+
+ switch (type) {
+ case T_ARRAY:
+ case T_OBJECT: {
+ if (UseCompressedOops && on_heap) {
+ Register co = tmp1;
+ if (val == noreg) {
+ __ li(co, 0);
+ } else {
+ co = not_null ? __ encode_heap_oop_not_null(tmp1, val) : __ encode_heap_oop(tmp1, val);
+ }
+ __ stw(co, ind_or_offs, base, tmp2);
+ } else {
+ if (val == noreg) {
+ val = tmp1;
+ __ li(val, 0);
+ }
+ __ std(val, ind_or_offs, base, tmp2);
+ }
+ break;
+ }
+ default: Unimplemented();
+ }
+}
+
+void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register dst,
+ Register tmp1, Register tmp2, bool needs_frame, Label *is_null) {
+ bool on_heap = (decorators & IN_HEAP) != 0;
+ bool on_root = (decorators & IN_ROOT) != 0;
+ assert(on_heap || on_root, "where?");
+ assert_different_registers(ind_or_offs.register_or_noreg(), dst, R0);
+
+ switch (type) {
+ case T_ARRAY:
+ case T_OBJECT: {
+ if (UseCompressedOops && on_heap) {
+ __ lwz(dst, ind_or_offs, base);
+ if (is_null) {
+ __ cmpwi(CCR0, dst, 0);
+ __ beq(CCR0, *is_null);
+ __ decode_heap_oop_not_null(dst);
+ } else {
+ __ decode_heap_oop(dst);
+ }
+ } else {
+ __ ld(dst, ind_or_offs, base);
+ if (is_null) {
+ __ cmpdi(CCR0, dst, 0);
+ __ beq(CCR0, *is_null);
+ }
+ }
+ break;
+ }
+ default: Unimplemented();
+ }
+}
+
+void BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value,
+ Register tmp1, Register tmp2, bool needs_frame) {
+ Label done;
+ __ cmpdi(CCR0, value, 0);
+ __ beq(CCR0, done); // Use NULL as-is.
+
+ __ clrrdi(tmp1, value, JNIHandles::weak_tag_size);
+ __ ld(value, 0, tmp1); // Resolve (untagged) jobject.
+
+ __ verify_oop(value);
+ __ bind(done);
+}
--- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -38,6 +38,18 @@
Register src, Register dst, Register count, Register preserve1, Register preserve2) {}
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Register count, Register preserve) {}
+
+ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame);
+
+ virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register dst,
+ Register tmp1, Register tmp2, bool needs_frame, Label *is_null = NULL);
+
+ virtual void resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2, bool needs_frame);
+
+ virtual void barrier_stubs_init() {}
};
#endif // CPU_PPC_GC_SHARED_BARRIERSETASSEMBLER_PPC_HPP
--- a/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -29,7 +29,6 @@
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/cardTableBarrierSetAssembler.hpp"
-#include "gc/shared/collectedHeap.hpp"
#include "interpreter/interp_masm.hpp"
#define __ masm->
@@ -44,7 +43,7 @@
void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr,
Register count, Register preserve) {
- CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(Universe::heap()->barrier_set());
+ CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
CardTable* ct = ctbs->card_table();
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
assert_different_registers(addr, count, R0);
@@ -72,3 +71,41 @@
__ bdnz(Lstore_loop);
__ bind(Lskip_loop);
}
+
+void CardTableBarrierSetAssembler::card_table_write(MacroAssembler* masm,
+ jbyte* byte_map_base,
+ Register tmp, Register obj) {
+ assert_different_registers(obj, tmp, R0);
+ __ load_const_optimized(tmp, (address)byte_map_base, R0);
+ __ srdi(obj, obj, CardTable::card_shift);
+ __ li(R0, CardTable::dirty_card_val());
+ if (UseConcMarkSweepGC) { __ membar(Assembler::StoreStore); }
+ __ stbx(R0, tmp, obj);
+}
+
+void CardTableBarrierSetAssembler::card_write_barrier_post(MacroAssembler* masm, Register store_addr, Register tmp) {
+ CardTableBarrierSet* bs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
+ card_table_write(masm, bs->card_table()->byte_map_base(), tmp, store_addr);
+}
+
+void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
+ bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
+ bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
+ bool precise = on_array || on_anonymous;
+
+ BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, needs_frame);
+
+ // No need for post barrier if storing NULL
+ if (val != noreg) {
+ if (precise) {
+ if (ind_or_offs.is_constant()) {
+ __ add_const_optimized(base, base, ind_or_offs.as_constant(), tmp1);
+ } else {
+ __ add(base, ind_or_offs.as_register(), base);
+ }
+ }
+ card_write_barrier_post(masm, base, tmp1);
+ }
+}
--- a/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -31,8 +31,16 @@
class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
- virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr,
- Register count, Register preserve);
+ virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
+ Register addr, Register count, Register preserve);
+
+ void card_table_write(MacroAssembler* masm, jbyte* byte_map_base, Register tmp, Register obj);
+
+ void card_write_barrier_post(MacroAssembler* masm, Register store_addr, Register tmp);
+
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame);
};
#endif // CPU_PPC_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_PPC_HPP
--- a/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -55,3 +55,19 @@
}
}
}
+
+void ModRefBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
+ BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, needs_frame);
+}
+
+void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
+ if (type == T_OBJECT || type == T_ARRAY) {
+ oop_store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, needs_frame);
+ } else {
+ BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, needs_frame);
+ }
+}
--- a/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/gc/shared/modRefBarrierSetAssembler_ppc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -29,17 +29,28 @@
#include "asm/macroAssembler.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
+// The ModRefBarrierSetAssembler filters away accesses on BasicTypes other
+// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected
+// accesses, which are overridden in the concrete BarrierSetAssembler.
+
class ModRefBarrierSetAssembler: public BarrierSetAssembler {
protected:
virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register from, Register to, Register count,
Register preserve1, Register preserve2) {}
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register preserve) {}
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame);
public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register src, Register dst, Register count, Register preserve1, Register preserve2);
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Register count, Register preserve);
+
+ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register base, RegisterOrConstant ind_or_offs, Register val,
+ Register tmp1, Register tmp2, Register tmp3, bool needs_frame);
};
#endif // CPU_PPC_GC_SHARED_MODREFBARRIERSETASSEMBLER_PPC_HPP
--- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -26,6 +26,8 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interp_masm_ppc.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "prims/jvmtiThreadState.hpp"
@@ -492,9 +494,8 @@
#endif
// Add in the index.
add(result, tmp, result);
- load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result, is_null);
- // The resulting oop is null if the reference is not yet resolved.
- // It is Universe::the_null_sentinel() if the reference resolved to NULL via condy.
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->load_at(this, IN_HEAP, T_OBJECT, result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result, tmp, R0, false, is_null);
}
// load cpool->resolved_klass_at(index)
@@ -2446,4 +2447,3 @@
// Dtrace support not implemented.
}
-
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -26,9 +26,9 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "compiler/disassembler.hpp"
-#include "gc/shared/cardTable.hpp"
-#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/resourceArea.hpp"
#include "nativeInst_ppc.hpp"
@@ -43,12 +43,6 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
#ifdef COMPILER2
#include "opto/intrinsicnode.hpp"
#endif
@@ -2579,7 +2573,6 @@
if (checkRetry) { bind(*checkRetry); }
addic_(retry_count_Reg, retry_count_Reg, -1);
blt(CCR0, doneRetry);
- smt_yield(); // Can't use wait(). No permission (SIGILL).
b(retryLabel);
bind(doneRetry);
}
@@ -2590,7 +2583,7 @@
// output: retry_count_Reg decremented by 1
// CTR is killed
void MacroAssembler::rtm_retry_lock_on_busy(Register retry_count_Reg, Register owner_addr_Reg, Label& retryLabel) {
- Label SpinLoop, doneRetry;
+ Label SpinLoop, doneRetry, doRetry;
addic_(retry_count_Reg, retry_count_Reg, -1);
blt(CCR0, doneRetry);
@@ -2599,16 +2592,26 @@
mtctr(R0);
}
+ // low thread priority
+ smt_prio_low();
bind(SpinLoop);
- smt_yield(); // Can't use waitrsv(). No permission (SIGILL).
if (RTMSpinLoopCount > 1) {
- bdz(retryLabel);
+ bdz(doRetry);
ld(R0, 0, owner_addr_Reg);
cmpdi(CCR0, R0, 0);
bne(CCR0, SpinLoop);
}
+ bind(doRetry);
+
+ // restore thread priority to default in userspace
+#ifdef LINUX
+ smt_prio_medium_low();
+#else
+ smt_prio_medium();
+#endif
+
b(retryLabel);
bind(doneRetry);
@@ -3031,213 +3034,11 @@
bne(CCR0, slow_path);
}
-
-// GC barrier helper macros
-
-// Write the card table byte if needed.
-void MacroAssembler::card_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp) {
- CardTableBarrierSet* bs =
- barrier_set_cast<CardTableBarrierSet>(Universe::heap()->barrier_set());
- assert(bs->kind() == BarrierSet::CardTableBarrierSet, "wrong barrier");
- CardTable* ct = bs->card_table();
-#ifdef ASSERT
- cmpdi(CCR0, Rnew_val, 0);
- asm_assert_ne("null oop not allowed", 0x321);
-#endif
- card_table_write(ct->byte_map_base(), Rtmp, Rstore_addr);
-}
-
-// Write the card table byte.
-void MacroAssembler::card_table_write(jbyte* byte_map_base, Register Rtmp, Register Robj) {
- assert_different_registers(Robj, Rtmp, R0);
- load_const_optimized(Rtmp, (address)byte_map_base, R0);
- srdi(Robj, Robj, CardTable::card_shift);
- li(R0, 0); // dirty
- if (UseConcMarkSweepGC) membar(Assembler::StoreStore);
- stbx(R0, Rtmp, Robj);
-}
-
-// Kills R31 if value is a volatile register.
void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp2, bool needs_frame) {
- Label done;
- cmpdi(CCR0, value, 0);
- beq(CCR0, done); // Use NULL as-is.
-
- clrrdi(tmp1, value, JNIHandles::weak_tag_size);
-#if INCLUDE_ALL_GCS
- if (UseG1GC) { andi_(tmp2, value, JNIHandles::weak_tag_mask); }
-#endif
- ld(value, 0, tmp1); // Resolve (untagged) jobject.
-
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- Label not_weak;
- beq(CCR0, not_weak); // Test for jweak tag.
- verify_oop(value);
- g1_write_barrier_pre(noreg, // obj
- noreg, // offset
- value, // pre_val
- tmp1, tmp2, needs_frame);
- bind(not_weak);
- }
-#endif // INCLUDE_ALL_GCS
- verify_oop(value);
- bind(done);
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->resolve_jobject(this, value, tmp1, tmp2, needs_frame);
}
-#if INCLUDE_ALL_GCS
-// General G1 pre-barrier generator.
-// Goal: record the previous value if it is not null.
-void MacroAssembler::g1_write_barrier_pre(Register Robj, RegisterOrConstant offset, Register Rpre_val,
- Register Rtmp1, Register Rtmp2, bool needs_frame) {
- Label runtime, filtered;
-
- // Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- lwz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread);
- } else {
- guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- lbz(Rtmp1, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), R16_thread);
- }
- cmpdi(CCR0, Rtmp1, 0);
- beq(CCR0, filtered);
-
- // Do we need to load the previous value?
- if (Robj != noreg) {
- // Load the previous value...
- if (UseCompressedOops) {
- lwz(Rpre_val, offset, Robj);
- } else {
- ld(Rpre_val, offset, Robj);
- }
- // Previous value has been loaded into Rpre_val.
- }
- assert(Rpre_val != noreg, "must have a real register");
-
- // Is the previous value null?
- cmpdi(CCR0, Rpre_val, 0);
- beq(CCR0, filtered);
-
- if (Robj != noreg && UseCompressedOops) {
- decode_heap_oop_not_null(Rpre_val);
- }
-
- // OK, it's not filtered, so we'll need to call enqueue. In the normal
- // case, pre_val will be a scratch G-reg, but there are some cases in
- // which it's an O-reg. In the first case, do a normal call. In the
- // latter, do a save here and call the frameless version.
-
- // Can we store original value in the thread's buffer?
- // Is index == 0?
- // (The index field is typed as size_t.)
- const Register Rbuffer = Rtmp1, Rindex = Rtmp2;
-
- ld(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()), R16_thread);
- cmpdi(CCR0, Rindex, 0);
- beq(CCR0, runtime); // If index == 0, goto runtime.
- ld(Rbuffer, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf()), R16_thread);
-
- addi(Rindex, Rindex, -wordSize); // Decrement index.
- std(Rindex, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index()), R16_thread);
-
- // Record the previous value.
- stdx(Rpre_val, Rbuffer, Rindex);
- b(filtered);
-
- bind(runtime);
-
- // May need to preserve LR. Also needed if current frame is not compatible with C calling convention.
- if (needs_frame) {
- save_LR_CR(Rtmp1);
- push_frame_reg_args(0, Rtmp2);
- }
-
- if (Rpre_val->is_volatile() && Robj == noreg) mr(R31, Rpre_val); // Save pre_val across C call if it was preloaded.
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), Rpre_val, R16_thread);
- if (Rpre_val->is_volatile() && Robj == noreg) mr(Rpre_val, R31); // restore
-
- if (needs_frame) {
- pop_frame();
- restore_LR_CR(Rtmp1);
- }
-
- bind(filtered);
-}
-
-// General G1 post-barrier generator
-// Store cross-region card.
-void MacroAssembler::g1_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp1, Register Rtmp2, Register Rtmp3, Label *filtered_ext) {
- Label runtime, filtered_int;
- Label& filtered = (filtered_ext != NULL) ? *filtered_ext : filtered_int;
- assert_different_registers(Rstore_addr, Rnew_val, Rtmp1, Rtmp2);
-
- G1BarrierSet* bs =
- barrier_set_cast<G1BarrierSet>(Universe::heap()->barrier_set());
- CardTable* ct = bs->card_table();
-
- // Does store cross heap regions?
- if (G1RSBarrierRegionFilter) {
- xorr(Rtmp1, Rstore_addr, Rnew_val);
- srdi_(Rtmp1, Rtmp1, HeapRegion::LogOfHRGrainBytes);
- beq(CCR0, filtered);
- }
-
- // Crosses regions, storing NULL?
-#ifdef ASSERT
- cmpdi(CCR0, Rnew_val, 0);
- asm_assert_ne("null oop not allowed (G1)", 0x322); // Checked by caller on PPC64, so following branch is obsolete:
- //beq(CCR0, filtered);
-#endif
-
- // Storing region crossing non-NULL, is card already dirty?
- assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
- const Register Rcard_addr = Rtmp1;
- Register Rbase = Rtmp2;
- load_const_optimized(Rbase, (address)ct->byte_map_base(), /*temp*/ Rtmp3);
-
- srdi(Rcard_addr, Rstore_addr, CardTable::card_shift);
-
- // Get the address of the card.
- lbzx(/*card value*/ Rtmp3, Rbase, Rcard_addr);
- cmpwi(CCR0, Rtmp3, (int)G1CardTable::g1_young_card_val());
- beq(CCR0, filtered);
-
- membar(Assembler::StoreLoad);
- lbzx(/*card value*/ Rtmp3, Rbase, Rcard_addr); // Reload after membar.
- cmpwi(CCR0, Rtmp3 /* card value */, CardTable::dirty_card_val());
- beq(CCR0, filtered);
-
- // Storing a region crossing, non-NULL oop, card is clean.
- // Dirty card and log.
- li(Rtmp3, CardTable::dirty_card_val());
- //release(); // G1: oops are allowed to get visible after dirty marking.
- stbx(Rtmp3, Rbase, Rcard_addr);
-
- add(Rcard_addr, Rbase, Rcard_addr); // This is the address which needs to get enqueued.
- Rbase = noreg; // end of lifetime
-
- const Register Rqueue_index = Rtmp2,
- Rqueue_buf = Rtmp3;
- ld(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_index()), R16_thread);
- cmpdi(CCR0, Rqueue_index, 0);
- beq(CCR0, runtime); // index == 0 then jump to runtime
- ld(Rqueue_buf, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_buf()), R16_thread);
-
- addi(Rqueue_index, Rqueue_index, -wordSize); // decrement index
- std(Rqueue_index, in_bytes(JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_index()), R16_thread);
-
- stdx(Rcard_addr, Rqueue_buf, Rqueue_index); // store card
- b(filtered);
-
- bind(runtime);
-
- // Save the live input values.
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), Rcard_addr, R16_thread);
-
- bind(filtered_int);
-}
-#endif // INCLUDE_ALL_GCS
-
// Values for last_Java_pc, and last_Java_sp must comply to the rules
// in frame_ppc.hpp.
void MacroAssembler::set_last_Java_frame(Register last_Java_sp, Register last_Java_pc) {
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -650,21 +650,8 @@
// Check if safepoint requested and if so branch
void safepoint_poll(Label& slow_path, Register temp_reg);
- // GC barrier support.
- void card_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp);
- void card_table_write(jbyte* byte_map_base, Register Rtmp, Register Robj);
-
void resolve_jobject(Register value, Register tmp1, Register tmp2, bool needs_frame);
-#if INCLUDE_ALL_GCS
- // General G1 pre-barrier generator.
- void g1_write_barrier_pre(Register Robj, RegisterOrConstant offset, Register Rpre_val,
- Register Rtmp1, Register Rtmp2, bool needs_frame = false);
- // General G1 post-barrier generator
- void g1_write_barrier_post(Register Rstore_addr, Register Rnew_val, Register Rtmp1,
- Register Rtmp2, Register Rtmp3, Label *filtered_ext = NULL);
-#endif
-
// Support for managing the JavaThread pointer (i.e.; the reference to
// thread-local information).
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -2495,7 +2495,7 @@
// --------------------------------------------------------------------------
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
- __ resolve_jobject(R3_RET, r_temp_1, r_temp_2, /* needs_frame */ false); // kills R31
+ __ resolve_jobject(R3_RET, r_temp_1, r_temp_2, /* needs_frame */ false);
}
if (CheckJNICalls) {
--- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -2032,7 +2032,7 @@
decorators |= ARRAYCOPY_ALIGNED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, T_OBJECT, R3_ARG1, R4_ARG2, R5_ARG3, noreg, noreg);
if (UseCompressedOops) {
@@ -2071,7 +2071,7 @@
decorators |= ARRAYCOPY_ALIGNED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, T_OBJECT, R3_ARG1, R4_ARG2, R5_ARG3, noreg, noreg);
if (UseCompressedOops) {
@@ -2164,7 +2164,7 @@
decorators |= AS_DEST_NOT_INITIALIZED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, T_OBJECT, R3_from, R4_to, R5_count, /* preserve: */ R6_ckoff, R7_ckval);
//inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr, R12_tmp, R3_RET);
--- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2015, 2017, SAP SE. All rights reserved.
+ * Copyright (c) 2015, 2018, SAP SE. All rights reserved.
* 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 "asm/macroAssembler.inline.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
@@ -402,7 +403,7 @@
break;
case T_OBJECT:
// JNIHandles::resolve result.
- __ resolve_jobject(R3_RET, R11_scratch1, R12_scratch2, /* needs_frame */ true); // kills R31
+ __ resolve_jobject(R3_RET, R11_scratch1, R31, /* needs_frame */ true); // kills R31
break;
case T_FLOAT:
break;
@@ -504,59 +505,50 @@
// regular method entry code to generate the NPE.
//
- if (UseG1GC) {
- address entry = __ pc();
+ address entry = __ pc();
- const int referent_offset = java_lang_ref_Reference::referent_offset;
- guarantee(referent_offset > 0, "referent offset not initialized");
+ const int referent_offset = java_lang_ref_Reference::referent_offset;
+ guarantee(referent_offset > 0, "referent offset not initialized");
- Label slow_path;
+ Label slow_path;
- // Debugging not possible, so can't use __ skip_if_jvmti_mode(slow_path, GR31_SCRATCH);
+ // Debugging not possible, so can't use __ skip_if_jvmti_mode(slow_path, GR31_SCRATCH);
- // In the G1 code we don't check if we need to reach a safepoint. We
- // continue and the thread will safepoint at the next bytecode dispatch.
-
- // If the receiver is null then it is OK to jump to the slow path.
- __ ld(R3_RET, Interpreter::stackElementSize, R15_esp); // get receiver
+ // In the G1 code we don't check if we need to reach a safepoint. We
+ // continue and the thread will safepoint at the next bytecode dispatch.
- // Check if receiver == NULL and go the slow path.
- __ cmpdi(CCR0, R3_RET, 0);
- __ beq(CCR0, slow_path);
+ // If the receiver is null then it is OK to jump to the slow path.
+ __ ld(R3_RET, Interpreter::stackElementSize, R15_esp); // get receiver
- // Load the value of the referent field.
- __ load_heap_oop(R3_RET, referent_offset, R3_RET);
+ // Check if receiver == NULL and go the slow path.
+ __ cmpdi(CCR0, R3_RET, 0);
+ __ beq(CCR0, slow_path);
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer. Note with
- // these parameters the pre-barrier does not generate
- // the load of the previous value.
+ // Load the value of the referent field.
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->load_at(_masm, IN_HEAP | ON_WEAK_OOP_REF, T_OBJECT,
+ R3_RET, referent_offset, R3_RET,
+ /* non-volatile temp */ R31, R11_scratch1, true);
- // Restore caller sp for c2i case.
-#ifdef ASSERT
- __ ld(R9_ARG7, 0, R1_SP);
- __ ld(R10_ARG8, 0, R21_sender_SP);
- __ cmpd(CCR0, R9_ARG7, R10_ARG8);
- __ asm_assert_eq("backlink", 0x544);
-#endif // ASSERT
- __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer. Note with
+ // these parameters the pre-barrier does not generate
+ // the load of the previous value.
- __ g1_write_barrier_pre(noreg, // obj
- noreg, // offset
- R3_RET, // pre_val
- R11_scratch1, // tmp
- R12_scratch2, // tmp
- true); // needs_frame
+ // Restore caller sp for c2i case.
+#ifdef ASSERT
+ __ ld(R9_ARG7, 0, R1_SP);
+ __ ld(R10_ARG8, 0, R21_sender_SP);
+ __ cmpd(CCR0, R9_ARG7, R10_ARG8);
+ __ asm_assert_eq("backlink", 0x544);
+#endif // ASSERT
+ __ mr(R1_SP, R21_sender_SP); // Cut the stack back to where the caller started.
- __ blr();
+ __ blr();
- // Generate regular method entry.
- __ bind(slow_path);
- __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1);
- return entry;
- }
-
- return NULL;
+ __ bind(slow_path);
+ __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals), R11_scratch1);
+ return entry;
}
address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
--- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/interp_masm.hpp"
@@ -53,99 +54,29 @@
// Kills:
// Rbase, Rtmp
static void do_oop_store(InterpreterMacroAssembler* _masm,
- Register Rbase,
+ Register base,
RegisterOrConstant offset,
- Register Rval, // Noreg means always null.
- Register Rtmp1,
- Register Rtmp2,
- Register Rtmp3,
- BarrierSet::Name barrier,
- bool precise,
- bool check_null) {
- assert_different_registers(Rtmp1, Rtmp2, Rtmp3, Rval, Rbase);
-
- switch (barrier) {
-#if INCLUDE_ALL_GCS
- case BarrierSet::G1BarrierSet:
- {
- // Load and record the previous value.
- __ g1_write_barrier_pre(Rbase, offset,
- Rtmp3, /* holder of pre_val ? */
- Rtmp1, Rtmp2, false /* frame */);
-
- Label Lnull, Ldone;
- if (Rval != noreg) {
- if (check_null) {
- __ cmpdi(CCR0, Rval, 0);
- __ beq(CCR0, Lnull);
- }
- __ store_heap_oop_not_null(Rval, offset, Rbase, /*Rval must stay uncompressed.*/ Rtmp1);
- // Mark the card.
- if (!(offset.is_constant() && offset.as_constant() == 0) && precise) {
- __ add(Rbase, offset, Rbase);
- }
- __ g1_write_barrier_post(Rbase, Rval, Rtmp1, Rtmp2, Rtmp3, /*filtered (fast path)*/ &Ldone);
- if (check_null) { __ b(Ldone); }
- }
-
- if (Rval == noreg || check_null) { // Store null oop.
- Register Rnull = Rval;
- __ bind(Lnull);
- if (Rval == noreg) {
- Rnull = Rtmp1;
- __ li(Rnull, 0);
- }
- if (UseCompressedOops) {
- __ stw(Rnull, offset, Rbase);
- } else {
- __ std(Rnull, offset, Rbase);
- }
- }
- __ bind(Ldone);
- }
- break;
-#endif // INCLUDE_ALL_GCS
- case BarrierSet::CardTableBarrierSet:
- {
- Label Lnull, Ldone;
- if (Rval != noreg) {
- if (check_null) {
- __ cmpdi(CCR0, Rval, 0);
- __ beq(CCR0, Lnull);
- }
- __ store_heap_oop_not_null(Rval, offset, Rbase, /*Rval should better stay uncompressed.*/ Rtmp1);
- // Mark the card.
- if (!(offset.is_constant() && offset.as_constant() == 0) && precise) {
- __ add(Rbase, offset, Rbase);
- }
- __ card_write_barrier_post(Rbase, Rval, Rtmp1);
- if (check_null) {
- __ b(Ldone);
- }
- }
-
- if (Rval == noreg || check_null) { // Store null oop.
- Register Rnull = Rval;
- __ bind(Lnull);
- if (Rval == noreg) {
- Rnull = Rtmp1;
- __ li(Rnull, 0);
- }
- if (UseCompressedOops) {
- __ stw(Rnull, offset, Rbase);
- } else {
- __ std(Rnull, offset, Rbase);
- }
- }
- __ bind(Ldone);
- }
- break;
- case BarrierSet::ModRef:
- ShouldNotReachHere();
- break;
- default:
- ShouldNotReachHere();
- }
+ Register val, // Noreg means always null.
+ Register tmp1,
+ Register tmp2,
+ Register tmp3,
+ DecoratorSet decorators) {
+ assert_different_registers(tmp1, tmp2, tmp3, val, base);
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->store_at(_masm, decorators, T_OBJECT, base, offset, val, tmp1, tmp2, tmp3, false);
+}
+
+static void do_oop_load(InterpreterMacroAssembler* _masm,
+ Register base,
+ RegisterOrConstant offset,
+ Register dst,
+ Register tmp1,
+ Register tmp2,
+ DecoratorSet decorators) {
+ assert_different_registers(base, tmp1, tmp2);
+ assert_different_registers(dst, tmp1, tmp2);
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->load_at(_masm, decorators, T_OBJECT, base, offset, dst, tmp1, tmp2, false);
}
// ============================================================================
@@ -755,9 +686,11 @@
// result tos: array
const Register Rload_addr = R3_ARG1,
Rarray = R4_ARG2,
- Rtemp = R5_ARG3;
+ Rtemp = R5_ARG3,
+ Rtemp2 = R31;
__ index_check(Rarray, R17_tos /* index */, UseCompressedOops ? 2 : LogBytesPerWord, Rtemp, Rload_addr);
- __ load_heap_oop(R17_tos, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Rload_addr);
+ do_oop_load(_masm, Rload_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos, Rtemp, Rtemp2,
+ IN_HEAP | IN_HEAP_ARRAY);
__ verify_oop(R17_tos);
//__ dcbt(R17_tos); // prefetch
}
@@ -1084,14 +1017,14 @@
__ bind(Lis_null);
do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), noreg /* 0 */,
- Rscratch, Rscratch2, Rscratch3, _bs->kind(), true /* precise */, false /* check_null */);
+ Rscratch, Rscratch2, Rscratch3, IN_HEAP | IN_HEAP_ARRAY);
__ profile_null_seen(Rscratch, Rscratch2);
__ b(Ldone);
// Store is OK.
__ bind(Lstore_ok);
do_oop_store(_masm, Rstore_addr, arrayOopDesc::base_offset_in_bytes(T_OBJECT), R17_tos /* value */,
- Rscratch, Rscratch2, Rscratch3, _bs->kind(), true /* precise */, false /* check_null */);
+ Rscratch, Rscratch2, Rscratch3, IN_HEAP | IN_HEAP_ARRAY | OOP_NOT_NULL);
__ bind(Ldone);
// Adjust sp (pops array, index and value).
@@ -2714,7 +2647,7 @@
__ fence(); // Volatile entry point (one instruction before non-volatile_entry point).
assert(branch_table[atos] == 0, "can't compute twice");
branch_table[atos] = __ pc(); // non-volatile_entry point
- __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj);
+ do_oop_load(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, /* nv temp */ Rflags, IN_HEAP);
__ verify_oop(R17_tos);
__ push(atos);
//__ dcbt(R17_tos); // prefetch
@@ -3047,7 +2980,7 @@
branch_table[atos] = __ pc(); // non-volatile_entry point
__ pop(atos);
if (!is_static) { pop_and_check_object(Rclass_or_obj); } // kills R11_scratch1
- do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, _bs->kind(), false /* precise */, true /* check null */);
+ do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
if (!is_static && rc == may_rewrite) {
patch_bytecode(Bytecodes::_fast_aputfield, Rbc, Rscratch, true, byte_no);
}
@@ -3122,7 +3055,7 @@
switch(bytecode()) {
case Bytecodes::_fast_aputfield:
// Store into the field.
- do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, _bs->kind(), false /* precise */, true /* check null */);
+ do_oop_store(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, Rscratch2, Rscratch3, IN_HEAP);
break;
case Bytecodes::_fast_iputfield:
@@ -3196,13 +3129,13 @@
switch(bytecode()) {
case Bytecodes::_fast_agetfield:
{
- __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj);
+ do_oop_load(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, /* nv temp */ Rflags, IN_HEAP);
__ verify_oop(R17_tos);
__ dispatch_epilog(state, Bytecodes::length_for(bytecode()));
__ bind(LisVolatile);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
- __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj);
+ do_oop_load(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, /* nv temp */ Rflags, IN_HEAP);
__ verify_oop(R17_tos);
__ twi_0(R17_tos);
__ isync();
@@ -3336,13 +3269,13 @@
switch(state) {
case atos:
{
- __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj);
+ do_oop_load(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, /* nv temp */ Rflags, IN_HEAP);
__ verify_oop(R17_tos);
__ dispatch_epilog(state, Bytecodes::length_for(bytecode()) - 1); // Undo bcp increment.
__ bind(LisVolatile);
if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ fence(); }
- __ load_heap_oop(R17_tos, (RegisterOrConstant)Roffset, Rclass_or_obj);
+ do_oop_load(_masm, Rclass_or_obj, Roffset, R17_tos, Rscratch, /* nv temp */ Rflags, IN_HEAP);
__ verify_oop(R17_tos);
__ twi_0(R17_tos);
__ isync();
--- a/src/hotspot/cpu/s390/assembler_s390.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/assembler_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -40,7 +40,6 @@
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/heapRegion.hpp"
#endif
--- a/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/c1_Runtime1_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -45,6 +45,7 @@
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#endif
// Implementation of StubAssembler
@@ -767,7 +768,7 @@
case g1_pre_barrier_slow_id:
{ // Z_R1_scratch: previous value of memory
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ should_not_reach_here(FILE_AND_LINE);
break;
@@ -780,15 +781,9 @@
Register tmp2 = Z_R7;
Label refill, restart, marking_not_active;
- int satb_q_active_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active());
- int satb_q_index_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_index());
- int satb_q_buf_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf());
+ int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
+ int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
+ int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
// Save tmp registers (see assertion in G1PreBarrierStub::emit_code()).
__ z_stg(tmp, 0*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
@@ -836,7 +831,7 @@
case g1_post_barrier_slow_id:
{ // Z_R1_scratch: oop address, address of updated memory slot
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ should_not_reach_here(FILE_AND_LINE);
break;
@@ -890,10 +885,8 @@
// Save registers used below (see assertion in G1PreBarrierStub::emit_code()).
__ z_stg(r2, 1*BytesPerWord + FrameMap::first_available_sp_in_frame, Z_SP);
- ByteSize dirty_card_q_index_byte_offset =
- JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_index();
- ByteSize dirty_card_q_buf_byte_offset =
- JavaThread::dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_buf();
+ ByteSize dirty_card_q_index_byte_offset = G1ThreadLocalData::dirty_card_queue_index_offset();
+ ByteSize dirty_card_q_buf_byte_offset = G1ThreadLocalData::dirty_card_queue_buffer_offset();
__ bind(restart);
--- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -29,10 +29,10 @@
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1BarrierSetAssembler.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
-#include "gc/shared/collectedHeap.hpp"
-#include "runtime/thread.hpp"
#include "interpreter/interp_masm.hpp"
+#include "runtime/sharedRuntime.hpp"
#define __ masm->
@@ -49,8 +49,7 @@
assert_different_registers(addr, Z_R0_scratch); // would be destroyed by push_frame()
assert_different_registers(count, Z_R0_scratch); // would be destroyed by push_frame()
Register Rtmp1 = Z_R0_scratch;
- const int active_offset = in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active());
+ const int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ load_and_test_int(Rtmp1, Address(Z_thread, active_offset));
} else {
@@ -90,3 +89,321 @@
__ z_br(Z_R1); // Branch without linking, callee will return to stub caller.
}
}
+
+void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& src, Register dst, Register tmp1, Register tmp2, Label *is_null) {
+ bool on_oop = type == T_OBJECT || type == T_ARRAY;
+ bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
+ bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
+ bool on_reference = on_weak || on_phantom;
+ Label done;
+ if (on_oop && on_reference && is_null == NULL) { is_null = &done; }
+ ModRefBarrierSetAssembler::load_at(masm, decorators, type, src, dst, tmp1, tmp2, is_null);
+ if (on_oop && on_reference) {
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer.
+ g1_write_barrier_pre(masm, decorators | OOP_NOT_NULL,
+ NULL /* obj */,
+ dst /* pre_val */,
+ noreg/* preserve */ ,
+ tmp1, tmp2 /* tmp */,
+ true /* pre_val_needed */);
+ }
+ __ bind(done);
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, DecoratorSet decorators,
+ const Address* obj,
+ Register Rpre_val, // Ideally, this is a non-volatile register.
+ Register Rval, // Will be preserved.
+ Register Rtmp1, // If Rpre_val is volatile, either Rtmp1
+ Register Rtmp2, // or Rtmp2 has to be non-volatile.
+ bool pre_val_needed // Save Rpre_val across runtime call, caller uses it.
+ ) {
+
+ bool not_null = (decorators & OOP_NOT_NULL) != 0,
+ preloaded = obj == NULL;
+
+ const Register Robj = obj ? obj->base() : noreg,
+ Roff = obj ? obj->index() : noreg;
+ const int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
+ const int buffer_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
+ const int index_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
+ assert_different_registers(Rtmp1, Rtmp2, Z_R0_scratch); // None of the Rtmp<i> must be Z_R0!!
+ assert_different_registers(Robj, Z_R0_scratch); // Used for addressing. Furthermore, push_frame destroys Z_R0!!
+ assert_different_registers(Rval, Z_R0_scratch); // push_frame destroys Z_R0!!
+
+ Label callRuntime, filtered;
+
+ BLOCK_COMMENT("g1_write_barrier_pre {");
+
+ // Is marking active?
+ // Note: value is loaded for test purposes only. No further use here.
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ load_and_test_int(Rtmp1, Address(Z_thread, active_offset));
+ } else {
+ guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ load_and_test_byte(Rtmp1, Address(Z_thread, active_offset));
+ }
+ __ z_bre(filtered); // Activity indicator is zero, so there is no marking going on currently.
+
+ assert(Rpre_val != noreg, "must have a real register");
+
+
+ // If an object is given, we need to load the previous value into Rpre_val.
+ if (obj) {
+ // Load the previous value...
+ if (UseCompressedOops) {
+ __ z_llgf(Rpre_val, *obj);
+ } else {
+ __ z_lg(Rpre_val, *obj);
+ }
+ }
+
+ // Is the previous value NULL?
+ // If so, we don't need to record it and we're done.
+ // Note: pre_val is loaded, decompressed and stored (directly or via runtime call).
+ // Register contents is preserved across runtime call if caller requests to do so.
+ if (preloaded && not_null) {
+#ifdef ASSERT
+ __ z_ltgr(Rpre_val, Rpre_val);
+ __ asm_assert_ne("null oop not allowed (G1 pre)", 0x321); // Checked by caller.
+#endif
+ } else {
+ __ z_ltgr(Rpre_val, Rpre_val);
+ __ z_bre(filtered); // previous value is NULL, so we don't need to record it.
+ }
+
+ // Decode the oop now. We know it's not NULL.
+ if (Robj != noreg && UseCompressedOops) {
+ __ oop_decoder(Rpre_val, Rpre_val, /*maybeNULL=*/false);
+ }
+
+ // OK, it's not filtered, so we'll need to call enqueue.
+
+ // We can store the original value in the thread's buffer
+ // only if index > 0. Otherwise, we need runtime to handle.
+ // (The index field is typed as size_t.)
+ Register Rbuffer = Rtmp1, Rindex = Rtmp2;
+ assert_different_registers(Rbuffer, Rindex, Rpre_val);
+
+ __ z_lg(Rbuffer, buffer_offset, Z_thread);
+
+ __ load_and_test_long(Rindex, Address(Z_thread, index_offset));
+ __ z_bre(callRuntime); // If index == 0, goto runtime.
+
+ __ add2reg(Rindex, -wordSize); // Decrement index.
+ __ z_stg(Rindex, index_offset, Z_thread);
+
+ // Record the previous value.
+ __ z_stg(Rpre_val, 0, Rbuffer, Rindex);
+ __ z_bru(filtered); // We are done.
+
+ Rbuffer = noreg; // end of life
+ Rindex = noreg; // end of life
+
+ __ bind(callRuntime);
+
+ // Save some registers (inputs and result) over runtime call
+ // by spilling them into the top frame.
+ if (Robj != noreg && Robj->is_volatile()) {
+ __ z_stg(Robj, Robj->encoding()*BytesPerWord, Z_SP);
+ }
+ if (Roff != noreg && Roff->is_volatile()) {
+ __ z_stg(Roff, Roff->encoding()*BytesPerWord, Z_SP);
+ }
+ if (Rval != noreg && Rval->is_volatile()) {
+ __ z_stg(Rval, Rval->encoding()*BytesPerWord, Z_SP);
+ }
+
+ // Save Rpre_val (result) over runtime call.
+ Register Rpre_save = Rpre_val;
+ if ((Rpre_val == Z_R0_scratch) || (pre_val_needed && Rpre_val->is_volatile())) {
+ guarantee(!Rtmp1->is_volatile() || !Rtmp2->is_volatile(), "oops!");
+ Rpre_save = !Rtmp1->is_volatile() ? Rtmp1 : Rtmp2;
+ }
+ __ lgr_if_needed(Rpre_save, Rpre_val);
+
+ // Push frame to protect top frame with return pc and spilled register values.
+ __ save_return_pc();
+ __ push_frame_abi160(0); // Will use Z_R0 as tmp.
+
+ // Rpre_val may be destroyed by push_frame().
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), Rpre_save, Z_thread);
+
+ __ pop_frame();
+ __ restore_return_pc();
+
+ // Restore spilled values.
+ if (Robj != noreg && Robj->is_volatile()) {
+ __ z_lg(Robj, Robj->encoding()*BytesPerWord, Z_SP);
+ }
+ if (Roff != noreg && Roff->is_volatile()) {
+ __ z_lg(Roff, Roff->encoding()*BytesPerWord, Z_SP);
+ }
+ if (Rval != noreg && Rval->is_volatile()) {
+ __ z_lg(Rval, Rval->encoding()*BytesPerWord, Z_SP);
+ }
+ if (pre_val_needed && Rpre_val->is_volatile()) {
+ __ lgr_if_needed(Rpre_val, Rpre_save);
+ }
+
+ __ bind(filtered);
+ BLOCK_COMMENT("} g1_write_barrier_pre");
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators, Register Rstore_addr, Register Rnew_val,
+ Register Rtmp1, Register Rtmp2, Register Rtmp3) {
+ bool not_null = (decorators & OOP_NOT_NULL) != 0;
+
+ assert_different_registers(Rstore_addr, Rnew_val, Rtmp1, Rtmp2); // Most probably, Rnew_val == Rtmp3.
+
+ Label callRuntime, filtered;
+
+ CardTableBarrierSet* ct = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
+ assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code");
+
+ BLOCK_COMMENT("g1_write_barrier_post {");
+
+ // Does store cross heap regions?
+ // It does if the two addresses specify different grain addresses.
+ if (G1RSBarrierRegionFilter) {
+ if (VM_Version::has_DistinctOpnds()) {
+ __ z_xgrk(Rtmp1, Rstore_addr, Rnew_val);
+ } else {
+ __ z_lgr(Rtmp1, Rstore_addr);
+ __ z_xgr(Rtmp1, Rnew_val);
+ }
+ __ z_srag(Rtmp1, Rtmp1, HeapRegion::LogOfHRGrainBytes);
+ __ z_bre(filtered);
+ }
+
+ // Crosses regions, storing NULL?
+ if (not_null) {
+#ifdef ASSERT
+ __ z_ltgr(Rnew_val, Rnew_val);
+ __ asm_assert_ne("null oop not allowed (G1 post)", 0x322); // Checked by caller.
+#endif
+ } else {
+ __ z_ltgr(Rnew_val, Rnew_val);
+ __ z_bre(filtered);
+ }
+
+ Rnew_val = noreg; // end of lifetime
+
+ // Storing region crossing non-NULL, is card already dirty?
+ assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code");
+ assert_different_registers(Rtmp1, Rtmp2, Rtmp3);
+ // Make sure not to use Z_R0 for any of these registers.
+ Register Rcard_addr = (Rtmp1 != Z_R0_scratch) ? Rtmp1 : Rtmp3;
+ Register Rbase = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp3;
+
+ // calculate address of card
+ __ load_const_optimized(Rbase, (address)ct->card_table()->byte_map_base()); // Card table base.
+ __ z_srlg(Rcard_addr, Rstore_addr, CardTable::card_shift); // Index into card table.
+ __ z_algr(Rcard_addr, Rbase); // Explicit calculation needed for cli.
+ Rbase = noreg; // end of lifetime
+
+ // Filter young.
+ assert((unsigned int)G1CardTable::g1_young_card_val() <= 255, "otherwise check this code");
+ __ z_cli(0, Rcard_addr, G1CardTable::g1_young_card_val());
+ __ z_bre(filtered);
+
+ // Check the card value. If dirty, we're done.
+ // This also avoids false sharing of the (already dirty) card.
+ __ z_sync(); // Required to support concurrent cleaning.
+ assert((unsigned int)G1CardTable::dirty_card_val() <= 255, "otherwise check this code");
+ __ z_cli(0, Rcard_addr, G1CardTable::dirty_card_val()); // Reload after membar.
+ __ z_bre(filtered);
+
+ // Storing a region crossing, non-NULL oop, card is clean.
+ // Dirty card and log.
+ __ z_mvi(0, Rcard_addr, G1CardTable::dirty_card_val());
+
+ Register Rcard_addr_x = Rcard_addr;
+ Register Rqueue_index = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp1;
+ Register Rqueue_buf = (Rtmp3 != Z_R0_scratch) ? Rtmp3 : Rtmp1;
+ const int qidx_off = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
+ const int qbuf_off = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
+ if ((Rcard_addr == Rqueue_buf) || (Rcard_addr == Rqueue_index)) {
+ Rcard_addr_x = Z_R0_scratch; // Register shortage. We have to use Z_R0.
+ }
+ __ lgr_if_needed(Rcard_addr_x, Rcard_addr);
+
+ __ load_and_test_long(Rqueue_index, Address(Z_thread, qidx_off));
+ __ z_bre(callRuntime); // Index == 0 then jump to runtime.
+
+ __ z_lg(Rqueue_buf, qbuf_off, Z_thread);
+
+ __ add2reg(Rqueue_index, -wordSize); // Decrement index.
+ __ z_stg(Rqueue_index, qidx_off, Z_thread);
+
+ __ z_stg(Rcard_addr_x, 0, Rqueue_index, Rqueue_buf); // Store card.
+ __ z_bru(filtered);
+
+ __ bind(callRuntime);
+
+ // TODO: do we need a frame? Introduced to be on the safe side.
+ bool needs_frame = true;
+ __ lgr_if_needed(Rcard_addr, Rcard_addr_x); // copy back asap. push_frame will destroy Z_R0_scratch!
+
+ // VM call need frame to access(write) O register.
+ if (needs_frame) {
+ __ save_return_pc();
+ __ push_frame_abi160(0); // Will use Z_R0 as tmp on old CPUs.
+ }
+
+ // Save the live input values.
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), Rcard_addr, Z_thread);
+
+ if (needs_frame) {
+ __ pop_frame();
+ __ restore_return_pc();
+ }
+
+ __ bind(filtered);
+
+ BLOCK_COMMENT("} g1_write_barrier_post");
+}
+
+void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
+ bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
+ bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
+ bool precise = on_array || on_anonymous;
+ // Load and record the previous value.
+ g1_write_barrier_pre(masm, decorators, &dst, tmp3, val, tmp1, tmp2, false);
+
+ BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
+
+ // No need for post barrier if storing NULL
+ if (val != noreg) {
+ const Register base = dst.base(),
+ idx = dst.index();
+ const intptr_t disp = dst.disp();
+ if (precise && (disp != 0 || idx != noreg)) {
+ __ add2reg_with_index(base, disp, idx, base);
+ }
+ g1_write_barrier_post(masm, decorators, base, val, tmp1, tmp2, tmp3);
+ }
+}
+
+void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2) {
+ NearLabel Ldone, Lnot_weak;
+ __ z_ltgr(tmp1, value);
+ __ z_bre(Ldone); // Use NULL result as-is.
+
+ __ z_nill(value, ~JNIHandles::weak_tag_mask);
+ __ z_lg(value, 0, value); // Resolve (untagged) jobject.
+
+ __ z_tmll(tmp1, JNIHandles::weak_tag_mask); // Test for jweak tag.
+ __ z_braz(Lnot_weak);
+ __ verify_oop(value);
+ DecoratorSet decorators = IN_ROOT | ON_PHANTOM_OOP_REF;
+ g1_write_barrier_pre(masm, decorators, (const Address*)NULL, value, noreg, tmp1, tmp2, true);
+ __ bind(Lnot_weak);
+ __ verify_oop(value);
+ __ bind(Ldone);
+}
+
+#undef __
--- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -31,10 +31,29 @@
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
- virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count);
- virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count, bool do_return);
+ virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count);
+ virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count,
+ bool do_return);
+
+ void g1_write_barrier_pre(MacroAssembler* masm, DecoratorSet decorators,
+ const Address* obj, // Address of oop or NULL if pre-loaded.
+ Register Rpre_val, // Ideally, this is a non-volatile register.
+ Register Rval, // Will be preserved.
+ Register Rtmp1, // If Rpre_val is volatile, either Rtmp1
+ Register Rtmp2, // or Rtmp2 has to be non-volatile.
+ bool pre_val_needed); // Save Rpre_val across runtime call, caller uses it.
+
+ void g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators, Register Rstore_addr, Register Rnew_val,
+ Register Rtmp1, Register Rtmp2, Register Rtmp3);
+
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3);
+
+ public:
+ virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& src, Register dst, Register tmp1, Register tmp2, Label *is_null = NULL);
+
+ virtual void resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2);
};
#endif // CPU_S390_GC_G1_G1BARRIERSETASSEMBLER_S390_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, SAP SE. All rights reserved.
+ * 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/shared/barrierSetAssembler.hpp"
+#include "interpreter/interp_masm.hpp"
+
+#define __ masm->
+
+void BarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register dst, Register count, bool do_return) {
+ if (do_return) { __ z_br(Z_R14); }
+}
+
+void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& addr, Register dst, Register tmp1, Register tmp2, Label *is_null) {
+ bool on_heap = (decorators & IN_HEAP) != 0;
+ bool on_root = (decorators & IN_ROOT) != 0;
+ assert(on_heap || on_root, "where?");
+
+ switch (type) {
+ case T_ARRAY:
+ case T_OBJECT: {
+ if (UseCompressedOops && on_heap) {
+ __ z_llgf(dst, addr);
+ if (is_null) {
+ __ compareU32_and_branch(dst, (intptr_t)0, Assembler::bcondEqual, *is_null);
+ __ oop_decoder(dst, dst, false);
+ } else {
+ __ oop_decoder(dst, dst, true);
+ }
+ } else {
+ __ z_lg(dst, addr);
+ if (is_null) {
+ __ compareU64_and_branch(dst, (intptr_t)0, Assembler::bcondEqual, *is_null);
+ }
+ }
+ break;
+ }
+ default: Unimplemented();
+ }
+}
+
+void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& addr, Register val, Register tmp1, Register tmp2, Register tmp3) {
+ bool on_heap = (decorators & IN_HEAP) != 0;
+ bool on_root = (decorators & IN_ROOT) != 0;
+ bool not_null = (decorators & OOP_NOT_NULL) != 0;
+ assert(on_heap || on_root, "where?");
+ assert_different_registers(val, tmp1, tmp2);
+
+ switch (type) {
+ case T_ARRAY:
+ case T_OBJECT: {
+ if (UseCompressedOops && on_heap) {
+ if (val == noreg) {
+ __ clear_mem(addr, 4);
+ } else if (Universe::narrow_oop_mode() == Universe::UnscaledNarrowOop) {
+ __ z_st(val, addr);
+ } else {
+ Register tmp = (tmp1 != Z_R1) ? tmp1 : tmp2; // Avoid tmp == Z_R1 (see oop_encoder).
+ __ oop_encoder(tmp, val, !not_null);
+ __ z_st(tmp, addr);
+ }
+ } else {
+ if (val == noreg) {
+ __ clear_mem(addr, 8);
+ } else {
+ __ z_stg(val, addr);
+ }
+ }
+ break;
+ }
+ default: Unimplemented();
+ }
+}
+
+void BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2) {
+ NearLabel Ldone;
+ __ z_ltgr(tmp1, value);
+ __ z_bre(Ldone); // Use NULL result as-is.
+
+ __ z_nill(value, ~JNIHandles::weak_tag_mask);
+ __ z_lg(value, 0, value); // Resolve (untagged) jobject.
+
+ __ verify_oop(value);
+ __ bind(Ldone);
+}
--- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,8 +23,8 @@
*
*/
-#ifndef CPU_S390_GC_G1_BARRIERSETASSEMBLER_S390_HPP
-#define CPU_S390_GC_G1_BARRIERSETASSEMBLER_S390_HPP
+#ifndef CPU_S390_GC_SHARED_BARRIERSETASSEMBLER_S390_HPP
+#define CPU_S390_GC_SHARED_BARRIERSETASSEMBLER_S390_HPP
#include "asm/macroAssembler.hpp"
#include "memory/allocation.hpp"
@@ -38,6 +38,15 @@
Register src, Register dst, Register count) {}
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Register count, bool do_return = false);
+
+ virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& addr, Register dst, Register tmp1, Register tmp2, Label *is_null = NULL);
+ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& addr, Register val, Register tmp1, Register tmp2, Register tmp3);
+
+ virtual void resolve_jobject(MacroAssembler* masm, Register value, Register tmp1, Register tmp2);
+
+ virtual void barrier_stubs_init() {}
};
-#endif // CPU_S390_GC_G1_BARRIERSETASSEMBLER_S390_HPP
+#endif // CPU_S390_GC_SHARED_BARRIERSETASSEMBLER_S390_HPP
--- a/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -29,7 +29,6 @@
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/cardTableBarrierSetAssembler.hpp"
-#include "gc/shared/collectedHeap.hpp"
#include "interpreter/interp_masm.hpp"
#define __ masm->
@@ -46,7 +45,7 @@
void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count,
bool do_return) {
- CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(Universe::heap()->barrier_set());
+ CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
CardTable* ct = ctbs->card_table();
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
@@ -139,3 +138,38 @@
__ bind(done);
}
+
+void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register store_addr, Register tmp) {
+ // Does a store check for the oop in register obj. The content of
+ // register obj is destroyed afterwards.
+ CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
+ CardTable* ct = ctbs->card_table();
+ assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
+
+ assert_different_registers(store_addr, tmp);
+
+ __ z_srlg(store_addr, store_addr, CardTable::card_shift);
+ __ load_absolute_address(tmp, (address)ct->byte_map_base());
+ __ z_agr(store_addr, tmp);
+ __ z_mvi(0, store_addr, CardTable::dirty_card_val());
+}
+
+void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
+ bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
+ bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
+ bool precise = on_array || on_anonymous;
+
+ BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
+
+ // No need for post barrier if storing NULL
+ if (val != noreg) {
+ const Register base = dst.base(),
+ idx = dst.index();
+ const intptr_t disp = dst.disp();
+ if (precise && (disp != 0 || idx != noreg)) {
+ __ add2reg_with_index(base, disp, idx, base);
+ }
+ store_check(masm, base, tmp1);
+ }
+}
--- a/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/gc/shared/cardTableBarrierSetAssembler_s390.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,16 +23,21 @@
*
*/
-#ifndef CPU_X86_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_X86_HPP
-#define CPU_X86_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_X86_HPP
+#ifndef CPU_S390_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_S390_HPP
+#define CPU_S390_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_S390_HPP
#include "asm/macroAssembler.hpp"
#include "gc/shared/modRefBarrierSetAssembler.hpp"
class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
+ void store_check(MacroAssembler* masm, Register store_addr, Register tmp);
+
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count,
bool do_return);
+
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3);
};
-#endif // CPU_X86_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_X86_HPP
+#endif // CPU_S390_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_S390_HPP
--- a/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -49,3 +49,17 @@
if (do_return) { __ z_br(Z_R14); }
}
}
+
+void ModRefBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
+ BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
+}
+
+void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
+ if (type == T_OBJECT || type == T_ARRAY) {
+ oop_store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
+ } else {
+ BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
+ }
+}
--- a/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/gc/shared/modRefBarrierSetAssembler_s390.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,23 +23,31 @@
*
*/
-#ifndef CPU_X86_GC_SHARED_MODREFBARRIERSETASSEMBLER_X86_HPP
-#define CPU_X86_GC_SHARED_MODREFBARRIERSETASSEMBLER_X86_HPP
+#ifndef CPU_S390_GC_SHARED_MODREFBARRIERSETASSEMBLER_S390_HPP
+#define CPU_S390_GC_SHARED_MODREFBARRIERSETASSEMBLER_S390_HPP
#include "asm/macroAssembler.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
+// The ModRefBarrierSetAssembler filters away accesses on BasicTypes other
+// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected
+// accesses, which are overridden in the concrete BarrierSetAssembler.
+
class ModRefBarrierSetAssembler: public BarrierSetAssembler {
protected:
virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count) {}
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count,
bool do_return);
-
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3);
public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register src, Register dst, Register count);
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Register count, bool do_return = false);
+
+ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3);
};
-#endif // CPU_X86_GC_SHARED_MODREFBARRIERSETASSEMBLER_X86_HPP
+#endif // CPU_S390_GC_SHARED_MODREFBARRIERSETASSEMBLER_S390_HPP
--- a/src/hotspot/cpu/s390/interp_masm_s390.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2017 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2018 SAP SE. All rights reserved.
* 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,8 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interp_masm_s390.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
@@ -42,7 +44,7 @@
#include "runtime/thread.inline.hpp"
// Implementation of InterpreterMacroAssembler.
-// This file specializes the assember with interpreter-specific macros.
+// This file specializes the assembler with interpreter-specific macros.
#ifdef PRODUCT
#define BLOCK_COMMENT(str)
@@ -389,9 +391,8 @@
bind(index_ok);
#endif
z_agr(result, index); // Address of indexed array element.
- load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result);
- // The resulting oop is null if the reference is not yet resolved.
- // It is Universe::the_null_sentinel() if the reference resolved to NULL via condy.
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->load_at(this, IN_HEAP, T_OBJECT, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT)), result, tmp, noreg);
}
// load cpool->resolved_klass_at(index)
@@ -2197,4 +2198,3 @@
unimplemented("verfiyFPU");
}
}
-
--- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2017, SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2018, SAP SE. All rights reserved.
* 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,7 +27,8 @@
#include "asm/codeBuffer.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "compiler/disassembler.hpp"
-#include "gc/shared/cardTable.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
@@ -51,12 +52,6 @@
#include "runtime/stubRoutines.hpp"
#include "utilities/events.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif
#include <ucontext.h>
@@ -3503,315 +3498,10 @@
// flag == NE indicates failure
}
-// Write to card table for modification at store_addr - register is destroyed afterwards.
-void MacroAssembler::card_write_barrier_post(Register store_addr, Register tmp) {
- BarrierSet* bs = Universe::heap()->barrier_set();
- CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
- CardTable* ct = ctbs->card_table();
- assert(bs->kind() == BarrierSet::CardTableBarrierSet, "wrong barrier");
- assert_different_registers(store_addr, tmp);
- z_srlg(store_addr, store_addr, CardTable::card_shift);
- load_absolute_address(tmp, (address)ct->byte_map_base());
- z_agr(store_addr, tmp);
- z_mvi(0, store_addr, 0); // Store byte 0.
-}
-
void MacroAssembler::resolve_jobject(Register value, Register tmp1, Register tmp2) {
- NearLabel Ldone;
- z_ltgr(tmp1, value);
- z_bre(Ldone); // Use NULL result as-is.
-
- z_nill(value, ~JNIHandles::weak_tag_mask);
- z_lg(value, 0, value); // Resolve (untagged) jobject.
-
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- NearLabel Lnot_weak;
- z_tmll(tmp1, JNIHandles::weak_tag_mask); // Test for jweak tag.
- z_braz(Lnot_weak);
- verify_oop(value);
- g1_write_barrier_pre(noreg /* obj */,
- noreg /* offset */,
- value /* pre_val */,
- noreg /* val */,
- tmp1 /* tmp1 */,
- tmp2 /* tmp2 */,
- true /* pre_val_needed */);
- bind(Lnot_weak);
- }
-#endif // INCLUDE_ALL_GCS
- verify_oop(value);
- bind(Ldone);
-}
-
-#if INCLUDE_ALL_GCS
-
-//------------------------------------------------------
-// General G1 pre-barrier generator.
-// Purpose: record the previous value if it is not null.
-// All non-tmps are preserved.
-//------------------------------------------------------
-// Note: Rpre_val needs special attention.
-// The flag pre_val_needed indicated that the caller of this emitter function
-// relies on Rpre_val containing the correct value, that is:
-// either the value it contained on entry to this code segment
-// or the value that was loaded into the register from (Robj+offset).
-//
-// Independent from this requirement, the contents of Rpre_val must survive
-// the push_frame() operation. push_frame() uses Z_R0_scratch by default
-// to temporarily remember the frame pointer.
-// If Rpre_val is assigned Z_R0_scratch by the caller, code must be emitted to
-// save it's value.
-void MacroAssembler::g1_write_barrier_pre(Register Robj,
- RegisterOrConstant offset,
- Register Rpre_val, // Ideally, this is a non-volatile register.
- Register Rval, // Will be preserved.
- Register Rtmp1, // If Rpre_val is volatile, either Rtmp1
- Register Rtmp2, // or Rtmp2 has to be non-volatile..
- bool pre_val_needed // Save Rpre_val across runtime call, caller uses it.
- ) {
- Label callRuntime, filtered;
- const int active_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active());
- const int buffer_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf());
- const int index_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index());
- assert_different_registers(Rtmp1, Rtmp2, Z_R0_scratch); // None of the Rtmp<i> must be Z_R0!!
- assert_different_registers(Robj, Z_R0_scratch); // Used for addressing. Furthermore, push_frame destroys Z_R0!!
- assert_different_registers(Rval, Z_R0_scratch); // push_frame destroys Z_R0!!
-
-#ifdef ASSERT
- // make sure the register is not Z_R0. Used for addressing. Furthermore, would be destroyed by push_frame.
- if (offset.is_register() && offset.as_register()->encoding() == 0) {
- tty->print_cr("Roffset(g1_write_barrier_pre) = %%r%d", offset.as_register()->encoding());
- assert(false, "bad register for offset");
- }
-#endif
-
- BLOCK_COMMENT("g1_write_barrier_pre {");
-
- // Is marking active?
- // Note: value is loaded for test purposes only. No further use here.
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- load_and_test_int(Rtmp1, Address(Z_thread, active_offset));
- } else {
- guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- load_and_test_byte(Rtmp1, Address(Z_thread, active_offset));
- }
- z_bre(filtered); // Activity indicator is zero, so there is no marking going on currently.
-
- assert(Rpre_val != noreg, "must have a real register");
-
-
- // If an object is given, we need to load the previous value into Rpre_val.
- if (Robj != noreg) {
- // Load the previous value...
- Register ixReg = offset.is_register() ? offset.register_or_noreg() : Z_R0;
- if (UseCompressedOops) {
- z_llgf(Rpre_val, offset.constant_or_zero(), ixReg, Robj);
- } else {
- z_lg(Rpre_val, offset.constant_or_zero(), ixReg, Robj);
- }
- }
-
- // Is the previous value NULL?
- // If so, we don't need to record it and we're done.
- // Note: pre_val is loaded, decompressed and stored (directly or via runtime call).
- // Register contents is preserved across runtime call if caller requests to do so.
- z_ltgr(Rpre_val, Rpre_val);
- z_bre(filtered); // previous value is NULL, so we don't need to record it.
-
- // Decode the oop now. We know it's not NULL.
- if (Robj != noreg && UseCompressedOops) {
- oop_decoder(Rpre_val, Rpre_val, /*maybeNULL=*/false);
- }
-
- // OK, it's not filtered, so we'll need to call enqueue.
-
- // We can store the original value in the thread's buffer
- // only if index > 0. Otherwise, we need runtime to handle.
- // (The index field is typed as size_t.)
- Register Rbuffer = Rtmp1, Rindex = Rtmp2;
- assert_different_registers(Rbuffer, Rindex, Rpre_val);
-
- z_lg(Rbuffer, buffer_offset, Z_thread);
-
- load_and_test_long(Rindex, Address(Z_thread, index_offset));
- z_bre(callRuntime); // If index == 0, goto runtime.
-
- add2reg(Rindex, -wordSize); // Decrement index.
- z_stg(Rindex, index_offset, Z_thread);
-
- // Record the previous value.
- z_stg(Rpre_val, 0, Rbuffer, Rindex);
- z_bru(filtered); // We are done.
-
- Rbuffer = noreg; // end of life
- Rindex = noreg; // end of life
-
- bind(callRuntime);
-
- // Save some registers (inputs and result) over runtime call
- // by spilling them into the top frame.
- if (Robj != noreg && Robj->is_volatile()) {
- z_stg(Robj, Robj->encoding()*BytesPerWord, Z_SP);
- }
- if (offset.is_register() && offset.as_register()->is_volatile()) {
- Register Roff = offset.as_register();
- z_stg(Roff, Roff->encoding()*BytesPerWord, Z_SP);
- }
- if (Rval != noreg && Rval->is_volatile()) {
- z_stg(Rval, Rval->encoding()*BytesPerWord, Z_SP);
- }
-
- // Save Rpre_val (result) over runtime call.
- Register Rpre_save = Rpre_val;
- if ((Rpre_val == Z_R0_scratch) || (pre_val_needed && Rpre_val->is_volatile())) {
- guarantee(!Rtmp1->is_volatile() || !Rtmp2->is_volatile(), "oops!");
- Rpre_save = !Rtmp1->is_volatile() ? Rtmp1 : Rtmp2;
- }
- lgr_if_needed(Rpre_save, Rpre_val);
-
- // Push frame to protect top frame with return pc and spilled register values.
- save_return_pc();
- push_frame_abi160(0); // Will use Z_R0 as tmp.
-
- // Rpre_val may be destroyed by push_frame().
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), Rpre_save, Z_thread);
-
- pop_frame();
- restore_return_pc();
-
- // Restore spilled values.
- if (Robj != noreg && Robj->is_volatile()) {
- z_lg(Robj, Robj->encoding()*BytesPerWord, Z_SP);
- }
- if (offset.is_register() && offset.as_register()->is_volatile()) {
- Register Roff = offset.as_register();
- z_lg(Roff, Roff->encoding()*BytesPerWord, Z_SP);
- }
- if (Rval != noreg && Rval->is_volatile()) {
- z_lg(Rval, Rval->encoding()*BytesPerWord, Z_SP);
- }
- if (pre_val_needed && Rpre_val->is_volatile()) {
- lgr_if_needed(Rpre_val, Rpre_save);
- }
-
- bind(filtered);
- BLOCK_COMMENT("} g1_write_barrier_pre");
-}
-
-// General G1 post-barrier generator.
-// Purpose: Store cross-region card.
-void MacroAssembler::g1_write_barrier_post(Register Rstore_addr,
- Register Rnew_val,
- Register Rtmp1,
- Register Rtmp2,
- Register Rtmp3) {
- Label callRuntime, filtered;
-
- assert_different_registers(Rstore_addr, Rnew_val, Rtmp1, Rtmp2); // Most probably, Rnew_val == Rtmp3.
-
- G1BarrierSet* bs = barrier_set_cast<G1BarrierSet>(Universe::heap()->barrier_set());
- CardTable* ct = bs->card_table();
- assert(bs->kind() == BarrierSet::G1BarrierSet, "wrong barrier");
-
- BLOCK_COMMENT("g1_write_barrier_post {");
-
- // Does store cross heap regions?
- // It does if the two addresses specify different grain addresses.
- if (G1RSBarrierRegionFilter) {
- if (VM_Version::has_DistinctOpnds()) {
- z_xgrk(Rtmp1, Rstore_addr, Rnew_val);
- } else {
- z_lgr(Rtmp1, Rstore_addr);
- z_xgr(Rtmp1, Rnew_val);
- }
- z_srag(Rtmp1, Rtmp1, HeapRegion::LogOfHRGrainBytes);
- z_bre(filtered);
- }
-
- // Crosses regions, storing NULL?
-#ifdef ASSERT
- z_ltgr(Rnew_val, Rnew_val);
- asm_assert_ne("null oop not allowed (G1)", 0x255); // TODO: also on z? Checked by caller on PPC64, so following branch is obsolete:
- z_bre(filtered); // Safety net: don't break if we have a NULL oop.
-#endif
- Rnew_val = noreg; // end of lifetime
-
- // Storing region crossing non-NULL, is card already dirty?
- assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
- assert_different_registers(Rtmp1, Rtmp2, Rtmp3);
- // Make sure not to use Z_R0 for any of these registers.
- Register Rcard_addr = (Rtmp1 != Z_R0_scratch) ? Rtmp1 : Rtmp3;
- Register Rbase = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp3;
-
- // calculate address of card
- load_const_optimized(Rbase, (address)ct->byte_map_base()); // Card table base.
- z_srlg(Rcard_addr, Rstore_addr, CardTable::card_shift); // Index into card table.
- z_algr(Rcard_addr, Rbase); // Explicit calculation needed for cli.
- Rbase = noreg; // end of lifetime
-
- // Filter young.
- assert((unsigned int)G1CardTable::g1_young_card_val() <= 255, "otherwise check this code");
- z_cli(0, Rcard_addr, (int)G1CardTable::g1_young_card_val());
- z_bre(filtered);
-
- // Check the card value. If dirty, we're done.
- // This also avoids false sharing of the (already dirty) card.
- z_sync(); // Required to support concurrent cleaning.
- assert((unsigned int)CardTable::dirty_card_val() <= 255, "otherwise check this code");
- z_cli(0, Rcard_addr, CardTable::dirty_card_val()); // Reload after membar.
- z_bre(filtered);
-
- // Storing a region crossing, non-NULL oop, card is clean.
- // Dirty card and log.
- z_mvi(0, Rcard_addr, CardTable::dirty_card_val());
-
- Register Rcard_addr_x = Rcard_addr;
- Register Rqueue_index = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp1;
- Register Rqueue_buf = (Rtmp3 != Z_R0_scratch) ? Rtmp3 : Rtmp1;
- const int qidx_off = in_bytes(JavaThread::dirty_card_queue_offset() + SATBMarkQueue::byte_offset_of_index());
- const int qbuf_off = in_bytes(JavaThread::dirty_card_queue_offset() + SATBMarkQueue::byte_offset_of_buf());
- if ((Rcard_addr == Rqueue_buf) || (Rcard_addr == Rqueue_index)) {
- Rcard_addr_x = Z_R0_scratch; // Register shortage. We have to use Z_R0.
- }
- lgr_if_needed(Rcard_addr_x, Rcard_addr);
-
- load_and_test_long(Rqueue_index, Address(Z_thread, qidx_off));
- z_bre(callRuntime); // Index == 0 then jump to runtime.
-
- z_lg(Rqueue_buf, qbuf_off, Z_thread);
-
- add2reg(Rqueue_index, -wordSize); // Decrement index.
- z_stg(Rqueue_index, qidx_off, Z_thread);
-
- z_stg(Rcard_addr_x, 0, Rqueue_index, Rqueue_buf); // Store card.
- z_bru(filtered);
-
- bind(callRuntime);
-
- // TODO: do we need a frame? Introduced to be on the safe side.
- bool needs_frame = true;
- lgr_if_needed(Rcard_addr, Rcard_addr_x); // copy back asap. push_frame will destroy Z_R0_scratch!
-
- // VM call need frame to access(write) O register.
- if (needs_frame) {
- save_return_pc();
- push_frame_abi160(0); // Will use Z_R0 as tmp on old CPUs.
- }
-
- // Save the live input values.
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), Rcard_addr, Z_thread);
-
- if (needs_frame) {
- pop_frame();
- restore_return_pc();
- }
-
- bind(filtered);
-
- BLOCK_COMMENT("} g1_write_barrier_post");
-}
-#endif // INCLUDE_ALL_GCS
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->resolve_jobject(this, value, tmp1, tmp2);
+}
// Last_Java_sp must comply to the rules in frame_s390.hpp.
void MacroAssembler::set_last_Java_frame(Register last_Java_sp, Register last_Java_pc, bool allow_relocation) {
--- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2017, SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -744,32 +744,8 @@
void compiler_fast_lock_object(Register oop, Register box, Register temp1, Register temp2, bool try_bias = UseBiasedLocking);
void compiler_fast_unlock_object(Register oop, Register box, Register temp1, Register temp2, bool try_bias = UseBiasedLocking);
- // Write to card table for modification at store_addr - register is destroyed afterwards.
- void card_write_barrier_post(Register store_addr, Register tmp);
-
void resolve_jobject(Register value, Register tmp1, Register tmp2);
-#if INCLUDE_ALL_GCS
- // General G1 pre-barrier generator.
- // Purpose: record the previous value if it is not null.
- // All non-tmps are preserved.
- void g1_write_barrier_pre(Register Robj,
- RegisterOrConstant offset,
- Register Rpre_val, // Ideally, this is a non-volatile register.
- Register Rval, // Will be preserved.
- Register Rtmp1, // If Rpre_val is volatile, either Rtmp1
- Register Rtmp2, // or Rtmp2 has to be non-volatile.
- bool pre_val_needed); // Save Rpre_val across runtime call, caller uses it.
-
- // General G1 post-barrier generator.
- // Purpose: Store cross-region card.
- void g1_write_barrier_post(Register Rstore_addr,
- Register Rnew_val,
- Register Rtmp1,
- Register Rtmp2,
- Register Rtmp3);
-#endif // INCLUDE_ALL_GCS
-
// Support for last Java frame (but use call_VM instead where possible).
private:
void set_last_Java_frame(Register last_Java_sp, Register last_Java_pc, bool allow_relocation);
--- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1308,7 +1308,7 @@
decorators |= ARRAYCOPY_ALIGNED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, T_OBJECT, Z_ARG1, Z_ARG2, Z_ARG3);
generate_disjoint_copy(aligned, size, true, true);
@@ -1400,7 +1400,7 @@
decorators |= ARRAYCOPY_ALIGNED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, T_OBJECT, Z_ARG1, Z_ARG2, Z_ARG3);
generate_conjoint_copy(aligned, size, true); // Must preserve ARG2, ARG3.
--- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2017, SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, SAP SE. All rights reserved.
* 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 "asm/macroAssembler.inline.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/abstractInterpreter.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
@@ -479,73 +480,55 @@
}
address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- // Inputs:
- // Z_ARG1 - receiver
- //
- // What we do:
- // - Load the referent field address.
- // - Load the value in the referent field.
- // - Pass that value to the pre-barrier.
- //
- // In the case of G1 this will record the value of the
- // referent in an SATB buffer if marking is active.
- // This will cause concurrent marking to mark the referent
- // field as live.
-
- Register scratch1 = Z_tmp_2;
- Register scratch2 = Z_tmp_3;
- Register pre_val = Z_RET; // return value
- // Z_esp is callers operand stack pointer, i.e. it points to the parameters.
- Register Rargp = Z_esp;
-
- Label slow_path;
- address entry = __ pc();
-
- const int referent_offset = java_lang_ref_Reference::referent_offset;
- guarantee(referent_offset > 0, "referent offset not initialized");
-
- BLOCK_COMMENT("Reference_get {");
-
- // If the receiver is null then it is OK to jump to the slow path.
- __ load_and_test_long(pre_val, Address(Rargp, Interpreter::stackElementSize)); // Get receiver.
- __ z_bre(slow_path);
-
- // Load the value of the referent field.
- __ load_heap_oop(pre_val, referent_offset, pre_val);
-
- // Restore caller sp for c2i case.
- __ resize_frame_absolute(Z_R10, Z_R0, true); // Cut the stack back to where the caller started.
-
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer.
- // Note:
- // With these parameters the write_barrier_pre does not
- // generate instructions to load the previous value.
- __ g1_write_barrier_pre(noreg, // obj
- noreg, // offset
- pre_val, // pre_val
- noreg, // no new val to preserve
- scratch1, // tmp
- scratch2, // tmp
- true); // pre_val_needed
-
- __ z_br(Z_R14);
-
- // Branch to previously generated regular method entry.
- __ bind(slow_path);
-
- address meth_entry = Interpreter::entry_for_kind(Interpreter::zerolocals);
- __ jump_to_entry(meth_entry, Z_R1);
-
- BLOCK_COMMENT("} Reference_get");
-
- return entry;
- }
-#endif // INCLUDE_ALL_GCS
-
- return NULL;
+ // Inputs:
+ // Z_ARG1 - receiver
+ //
+ // What we do:
+ // - Load the referent field address.
+ // - Load the value in the referent field.
+ // - Pass that value to the pre-barrier.
+ //
+ // In the case of G1 this will record the value of the
+ // referent in an SATB buffer if marking is active.
+ // This will cause concurrent marking to mark the referent
+ // field as live.
+
+ Register scratch1 = Z_tmp_2;
+ Register scratch2 = Z_tmp_3;
+ Register pre_val = Z_RET; // return value
+ // Z_esp is callers operand stack pointer, i.e. it points to the parameters.
+ Register Rargp = Z_esp;
+
+ Label slow_path;
+ address entry = __ pc();
+
+ const int referent_offset = java_lang_ref_Reference::referent_offset;
+ guarantee(referent_offset > 0, "referent offset not initialized");
+
+ BLOCK_COMMENT("Reference_get {");
+
+ // If the receiver is null then it is OK to jump to the slow path.
+ __ load_and_test_long(pre_val, Address(Rargp, Interpreter::stackElementSize)); // Get receiver.
+ __ z_bre(slow_path);
+
+ // Load the value of the referent field.
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->load_at(_masm, IN_HEAP | ON_WEAK_OOP_REF, T_OBJECT,
+ Address(pre_val, referent_offset), pre_val, scratch1, scratch2);
+
+ // Restore caller sp for c2i case.
+ __ resize_frame_absolute(Z_R10, Z_R0, true); // Cut the stack back to where the caller started.
+ __ z_br(Z_R14);
+
+ // Branch to previously generated regular method entry.
+ __ bind(slow_path);
+
+ address meth_entry = Interpreter::entry_for_kind(Interpreter::zerolocals);
+ __ jump_to_entry(meth_entry, Z_R1);
+
+ BLOCK_COMMENT("} Reference_get");
+
+ return entry;
}
address TemplateInterpreterGenerator::generate_StackOverflowError_handler() {
--- a/src/hotspot/cpu/s390/templateTable_s390.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/s390/templateTable_s390.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016, 2017 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2018 SAP SE. All rights reserved.
* 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 "asm/macroAssembler.inline.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/interp_masm.hpp"
@@ -192,97 +193,27 @@
// Do an oop store like *(base + offset) = val
// offset can be a register or a constant.
static void do_oop_store(InterpreterMacroAssembler* _masm,
- Register base,
- RegisterOrConstant offset,
- Register val,
- bool val_is_null, // == false does not guarantee that val really is not equal NULL.
- Register tmp1, // If tmp3 is volatile, either tmp1 or tmp2 must be
- Register tmp2, // non-volatile to hold a copy of pre_val across runtime calls.
- Register tmp3, // Ideally, this tmp register is non-volatile, as it is used to
- // hold pre_val (must survive runtime calls).
- BarrierSet::Name barrier,
- bool precise) {
- BLOCK_COMMENT("do_oop_store {");
- assert(val != noreg, "val must always be valid, even if it is zero");
- assert_different_registers(tmp1, tmp2, tmp3, val, base, offset.register_or_noreg());
- __ verify_oop(val);
- switch (barrier) {
-#if INCLUDE_ALL_GCS
- case BarrierSet::G1BarrierSet:
- {
-#ifdef ASSERT
- if (val_is_null) { // Check if the flag setting reflects reality.
- Label OK;
- __ z_ltgr(val, val);
- __ z_bre(OK);
- __ z_illtrap(0x11);
- __ bind(OK);
- }
-#endif
- Register pre_val = tmp3;
- // Load and record the previous value.
- __ g1_write_barrier_pre(base, offset, pre_val, val,
- tmp1, tmp2,
- false); // Needs to hold pre_val in non_volatile register?
-
- if (val_is_null) {
- __ store_heap_oop_null(val, offset, base);
- } else {
- Label Done;
- // val_is_null == false does not guarantee that val really is not equal NULL.
- // Checking for this case dynamically has some cost, but also some benefit (in GC).
- // It's hard to say if cost or benefit is greater.
- { Label OK;
- __ z_ltgr(val, val);
- __ z_brne(OK);
- __ store_heap_oop_null(val, offset, base);
- __ z_bru(Done);
- __ bind(OK);
- }
- // G1 barrier needs uncompressed oop for region cross check.
- // Store_heap_oop compresses the oop in the argument register.
- Register val_work = val;
- if (UseCompressedOops) {
- val_work = tmp3;
- __ z_lgr(val_work, val);
- }
- __ store_heap_oop_not_null(val_work, offset, base);
-
- // We need precise card marks for oop array stores.
- // Otherwise, cardmarking the object which contains the oop is sufficient.
- if (precise && !(offset.is_constant() && offset.as_constant() == 0)) {
- __ add2reg_with_index(base,
- offset.constant_or_zero(),
- offset.register_or_noreg(),
- base);
- }
- __ g1_write_barrier_post(base /* store_adr */, val, tmp1, tmp2, tmp3);
- __ bind(Done);
- }
- }
- break;
-#endif // INCLUDE_ALL_GCS
- case BarrierSet::CardTableBarrierSet:
- {
- if (val_is_null) {
- __ store_heap_oop_null(val, offset, base);
- } else {
- __ store_heap_oop(val, offset, base);
- // Flatten object address if needed.
- if (precise && ((offset.register_or_noreg() != noreg) || (offset.constant_or_zero() != 0))) {
- __ load_address(base, Address(base, offset.register_or_noreg(), offset.constant_or_zero()));
- }
- __ card_write_barrier_post(base, tmp1);
- }
- }
- break;
- case BarrierSet::ModRef:
- // fall through
- default:
- ShouldNotReachHere();
-
- }
- BLOCK_COMMENT("} do_oop_store");
+ const Address& addr,
+ Register val, // Noreg means always null.
+ Register tmp1,
+ Register tmp2,
+ Register tmp3,
+ DecoratorSet decorators) {
+ assert_different_registers(tmp1, tmp2, tmp3, val, addr.base());
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->store_at(_masm, decorators, T_OBJECT, addr, val, tmp1, tmp2, tmp3);
+}
+
+static void do_oop_load(InterpreterMacroAssembler* _masm,
+ const Address& addr,
+ Register dst,
+ Register tmp1,
+ Register tmp2,
+ DecoratorSet decorators) {
+ assert_different_registers(addr.base(), tmp1, tmp2);
+ assert_different_registers(dst, tmp1, tmp2);
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bs->load_at(_masm, decorators, T_OBJECT, addr, dst, tmp1, tmp2);
}
Address TemplateTable::at_bcp(int offset) {
@@ -923,8 +854,8 @@
Register index = Z_tos;
index_check(Z_tmp_1, index, shift);
// Now load array element.
- __ load_heap_oop(Z_tos,
- Address(Z_tmp_1, index, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
+ do_oop_load(_masm, Address(Z_tmp_1, index, arrayOopDesc::base_offset_in_bytes(T_OBJECT)), Z_tos,
+ Z_tmp_2, Z_tmp_3, IN_HEAP | IN_HEAP_ARRAY);
__ verify_oop(Z_tos);
}
@@ -1260,22 +1191,23 @@
__ load_absolute_address(tmp1, Interpreter::_throw_ArrayStoreException_entry);
__ z_br(tmp1);
- // Come here on success.
- __ bind(ok_is_subtype);
-
- // Now store using the appropriate barrier.
Register tmp3 = Rsub_klass;
- do_oop_store(_masm, Rstore_addr, (intptr_t)0/*offset*/, Rvalue, false/*val==null*/,
- tmp3, tmp2, tmp1, _bs->kind(), true);
- __ z_bru(done);
// Have a NULL in Rvalue.
__ bind(is_null);
__ profile_null_seen(tmp1);
// Store a NULL.
- do_oop_store(_masm, Rstore_addr, (intptr_t)0/*offset*/, Rvalue, true/*val==null*/,
- tmp3, tmp2, tmp1, _bs->kind(), true);
+ do_oop_store(_masm, Address(Rstore_addr, (intptr_t)0), noreg,
+ tmp3, tmp2, tmp1, IN_HEAP | IN_HEAP_ARRAY);
+ __ z_bru(done);
+
+ // Come here on success.
+ __ bind(ok_is_subtype);
+
+ // Now store using the appropriate barrier.
+ do_oop_store(_masm, Address(Rstore_addr, (intptr_t)0), Rvalue,
+ tmp3, tmp2, tmp1, IN_HEAP | IN_HEAP_ARRAY | OOP_NOT_NULL);
// Pop stack arguments.
__ bind(done);
@@ -2831,7 +2763,7 @@
// to here is compensated for by the fallthru to "Done".
{
unsigned int b_off = __ offset();
- __ load_heap_oop(Z_tos, field);
+ do_oop_load(_masm, field, Z_tos, Z_tmp_2, Z_tmp_3, IN_HEAP);
__ verify_oop(Z_tos);
__ push(atos);
if (do_rewrite) {
@@ -3160,8 +3092,8 @@
pop_and_check_object(obj);
}
// Store into the field
- do_oop_store(_masm, obj, off, Z_tos, false,
- oopStore_tmp1, oopStore_tmp2, oopStore_tmp3, _bs->kind(), false);
+ do_oop_store(_masm, Address(obj, off), Z_tos,
+ oopStore_tmp1, oopStore_tmp2, oopStore_tmp3, IN_HEAP);
if (do_rewrite) {
patch_bytecode(Bytecodes::_fast_aputfield, bc, Z_ARG5, true, byte_no);
}
@@ -3322,8 +3254,8 @@
// access field
switch (bytecode()) {
case Bytecodes::_fast_aputfield:
- do_oop_store(_masm, obj, field_offset, Z_tos, false,
- Z_ARG2, Z_ARG3, Z_ARG4, _bs->kind(), false);
+ do_oop_store(_masm, Address(obj, field_offset), Z_tos,
+ Z_ARG2, Z_ARG3, Z_ARG4, IN_HEAP);
break;
case Bytecodes::_fast_lputfield:
__ reg2mem_opt(Z_tos, field);
@@ -3414,7 +3346,7 @@
// access field
switch (bytecode()) {
case Bytecodes::_fast_agetfield:
- __ load_heap_oop(Z_tos, field);
+ do_oop_load(_masm, field, Z_tos, Z_tmp_1, Z_tmp_2, IN_HEAP);
__ verify_oop(Z_tos);
return;
case Bytecodes::_fast_lgetfield:
@@ -3470,7 +3402,7 @@
__ mem2reg_opt(Z_tos, Address(receiver, index), false);
break;
case atos:
- __ load_heap_oop(Z_tos, Address(receiver, index));
+ do_oop_load(_masm, Address(receiver, index), Z_tos, Z_tmp_1, Z_tmp_2, IN_HEAP);
__ verify_oop(Z_tos);
break;
case ftos:
--- a/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/c1_Runtime1_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -43,6 +43,7 @@
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#endif
// Implementation of StubAssembler
@@ -761,7 +762,7 @@
#if INCLUDE_ALL_GCS
case g1_pre_barrier_slow_id:
{ // G4: previous value of memory
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ save_frame(0);
__ set((int)id, O1);
@@ -777,15 +778,9 @@
Register tmp2 = G3_scratch;
Label refill, restart;
- int satb_q_active_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active());
- int satb_q_index_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_index());
- int satb_q_buf_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf());
+ int satb_q_active_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
+ int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
+ int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
// Is marking still active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
@@ -832,7 +827,7 @@
case g1_post_barrier_slow_id:
{
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ save_frame(0);
__ set((int)id, O1);
@@ -886,12 +881,8 @@
// these registers are now dead
addr = cardtable = tmp = noreg;
- int dirty_card_q_index_byte_offset =
- in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_index());
- int dirty_card_q_buf_byte_offset =
- in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf());
+ int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
+ int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
__ bind(restart);
--- a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -27,11 +27,10 @@
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/g1BarrierSetAssembler.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
-#include "gc/shared/collectedHeap.hpp"
#include "interpreter/interp_masm.hpp"
#include "runtime/sharedRuntime.hpp"
-#include "runtime/thread.hpp"
#include "utilities/macros.hpp"
#define __ masm->
@@ -46,11 +45,10 @@
Label filtered;
// Is marking active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- __ ld(G2, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), tmp);
+ __ ld(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp);
} else {
- guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1,
- "Assumption");
- __ ldsb(G2, in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active()), tmp);
+ guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ ldsb(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp);
}
// Is marking active?
__ cmp_and_br_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
@@ -91,3 +89,408 @@
__ delayed()->mov(count->after_save(), O1);
__ restore();
}
+
+#undef __
+
+static address satb_log_enqueue_with_frame = NULL;
+static u_char* satb_log_enqueue_with_frame_end = NULL;
+
+static address satb_log_enqueue_frameless = NULL;
+static u_char* satb_log_enqueue_frameless_end = NULL;
+
+static int EnqueueCodeSize = 128 DEBUG_ONLY( + 256); // Instructions?
+
+static void generate_satb_log_enqueue(bool with_frame) {
+ BufferBlob* bb = BufferBlob::create("enqueue_with_frame", EnqueueCodeSize);
+ CodeBuffer buf(bb);
+ MacroAssembler masm(&buf);
+
+#define __ masm.
+
+ address start = __ pc();
+ Register pre_val;
+
+ Label refill, restart;
+ if (with_frame) {
+ __ save_frame(0);
+ pre_val = I0; // Was O0 before the save.
+ } else {
+ pre_val = O0;
+ }
+
+ int satb_q_index_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
+ int satb_q_buf_byte_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
+
+ assert(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t) &&
+ in_bytes(SATBMarkQueue::byte_width_of_buf()) == sizeof(intptr_t),
+ "check sizes in assembly below");
+
+ __ bind(restart);
+
+ // Load the index into the SATB buffer. SATBMarkQueue::_index is a size_t
+ // so ld_ptr is appropriate.
+ __ ld_ptr(G2_thread, satb_q_index_byte_offset, L0);
+
+ // index == 0?
+ __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill);
+
+ __ ld_ptr(G2_thread, satb_q_buf_byte_offset, L1);
+ __ sub(L0, oopSize, L0);
+
+ __ st_ptr(pre_val, L1, L0); // [_buf + index] := I0
+ if (!with_frame) {
+ // Use return-from-leaf
+ __ retl();
+ __ delayed()->st_ptr(L0, G2_thread, satb_q_index_byte_offset);
+ } else {
+ // Not delayed.
+ __ st_ptr(L0, G2_thread, satb_q_index_byte_offset);
+ }
+ if (with_frame) {
+ __ ret();
+ __ delayed()->restore();
+ }
+ __ bind(refill);
+
+ address handle_zero =
+ CAST_FROM_FN_PTR(address,
+ &SATBMarkQueueSet::handle_zero_index_for_thread);
+ // This should be rare enough that we can afford to save all the
+ // scratch registers that the calling context might be using.
+ __ mov(G1_scratch, L0);
+ __ mov(G3_scratch, L1);
+ __ mov(G4, L2);
+ // We need the value of O0 above (for the write into the buffer), so we
+ // save and restore it.
+ __ mov(O0, L3);
+ // Since the call will overwrite O7, we save and restore that, as well.
+ __ mov(O7, L4);
+ __ call_VM_leaf(L5, handle_zero, G2_thread);
+ __ mov(L0, G1_scratch);
+ __ mov(L1, G3_scratch);
+ __ mov(L2, G4);
+ __ mov(L3, O0);
+ __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
+ __ delayed()->mov(L4, O7);
+
+ if (with_frame) {
+ satb_log_enqueue_with_frame = start;
+ satb_log_enqueue_with_frame_end = __ pc();
+ } else {
+ satb_log_enqueue_frameless = start;
+ satb_log_enqueue_frameless_end = __ pc();
+ }
+
+#undef __
+}
+
+#define __ masm->
+
+void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
+ Register obj,
+ Register index,
+ int offset,
+ Register pre_val,
+ Register tmp,
+ bool preserve_o_regs) {
+ Label filtered;
+
+ if (obj == noreg) {
+ // We are not loading the previous value so make
+ // sure that we don't trash the value in pre_val
+ // with the code below.
+ assert_different_registers(pre_val, tmp);
+ } else {
+ // We will be loading the previous value
+ // in this code so...
+ assert(offset == 0 || index == noreg, "choose one");
+ assert(pre_val == noreg, "check this code");
+ }
+
+ // Is marking active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ ld(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp);
+ } else {
+ guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ ldsb(G2, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), tmp);
+ }
+
+ // Is marking active?
+ __ cmp_and_br_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
+
+ // Do we need to load the previous value?
+ if (obj != noreg) {
+ // Load the previous value...
+ if (index == noreg) {
+ if (Assembler::is_simm13(offset)) {
+ __ load_heap_oop(obj, offset, tmp);
+ } else {
+ __ set(offset, tmp);
+ __ load_heap_oop(obj, tmp, tmp);
+ }
+ } else {
+ __ load_heap_oop(obj, index, tmp);
+ }
+ // Previous value has been loaded into tmp
+ pre_val = tmp;
+ }
+
+ assert(pre_val != noreg, "must have a real register");
+
+ // Is the previous value null?
+ __ cmp_and_brx_short(pre_val, G0, Assembler::equal, Assembler::pt, filtered);
+
+ // OK, it's not filtered, so we'll need to call enqueue. In the normal
+ // case, pre_val will be a scratch G-reg, but there are some cases in
+ // which it's an O-reg. In the first case, do a normal call. In the
+ // latter, do a save here and call the frameless version.
+
+ guarantee(pre_val->is_global() || pre_val->is_out(),
+ "Or we need to think harder.");
+
+ if (pre_val->is_global() && !preserve_o_regs) {
+ __ call(satb_log_enqueue_with_frame);
+ __ delayed()->mov(pre_val, O0);
+ } else {
+ __ save_frame(0);
+ __ call(satb_log_enqueue_frameless);
+ __ delayed()->mov(pre_val->after_save(), O0);
+ __ restore();
+ }
+
+ __ bind(filtered);
+}
+
+#undef __
+
+static address dirty_card_log_enqueue = 0;
+static u_char* dirty_card_log_enqueue_end = 0;
+
+// This gets to assume that o0 contains the object address.
+static void generate_dirty_card_log_enqueue(jbyte* byte_map_base) {
+ BufferBlob* bb = BufferBlob::create("dirty_card_enqueue", EnqueueCodeSize*2);
+ CodeBuffer buf(bb);
+ MacroAssembler masm(&buf);
+#define __ masm.
+ address start = __ pc();
+
+ Label not_already_dirty, restart, refill, young_card;
+
+ __ srlx(O0, CardTable::card_shift, O0);
+ AddressLiteral addrlit(byte_map_base);
+ __ set(addrlit, O1); // O1 := <card table base>
+ __ ldub(O0, O1, O2); // O2 := [O0 + O1]
+
+ __ cmp_and_br_short(O2, G1CardTable::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card);
+
+ __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
+ __ ldub(O0, O1, O2); // O2 := [O0 + O1]
+
+ assert(G1CardTable::dirty_card_val() == 0, "otherwise check this code");
+ __ cmp_and_br_short(O2, G0, Assembler::notEqual, Assembler::pt, not_already_dirty);
+
+ __ bind(young_card);
+ // We didn't take the branch, so we're already dirty: return.
+ // Use return-from-leaf
+ __ retl();
+ __ delayed()->nop();
+
+ // Not dirty.
+ __ bind(not_already_dirty);
+
+ // Get O0 + O1 into a reg by itself
+ __ add(O0, O1, O3);
+
+ // First, dirty it.
+ __ stb(G0, O3, G0); // [cardPtr] := 0 (i.e., dirty).
+
+ int dirty_card_q_index_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
+ int dirty_card_q_buf_byte_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
+ __ bind(restart);
+
+ // Load the index into the update buffer. DirtyCardQueue::_index is
+ // a size_t so ld_ptr is appropriate here.
+ __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, L0);
+
+ // index == 0?
+ __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill);
+
+ __ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, L1);
+ __ sub(L0, oopSize, L0);
+
+ __ st_ptr(O3, L1, L0); // [_buf + index] := I0
+ // Use return-from-leaf
+ __ retl();
+ __ delayed()->st_ptr(L0, G2_thread, dirty_card_q_index_byte_offset);
+
+ __ bind(refill);
+ address handle_zero =
+ CAST_FROM_FN_PTR(address,
+ &DirtyCardQueueSet::handle_zero_index_for_thread);
+ // This should be rare enough that we can afford to save all the
+ // scratch registers that the calling context might be using.
+ __ mov(G1_scratch, L3);
+ __ mov(G3_scratch, L5);
+ // We need the value of O3 above (for the write into the buffer), so we
+ // save and restore it.
+ __ mov(O3, L6);
+ // Since the call will overwrite O7, we save and restore that, as well.
+ __ mov(O7, L4);
+
+ __ call_VM_leaf(L7_thread_cache, handle_zero, G2_thread);
+ __ mov(L3, G1_scratch);
+ __ mov(L5, G3_scratch);
+ __ mov(L6, O3);
+ __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
+ __ delayed()->mov(L4, O7);
+
+ dirty_card_log_enqueue = start;
+ dirty_card_log_enqueue_end = __ pc();
+ // XXX Should have a guarantee here about not going off the end!
+ // Does it already do so? Do an experiment...
+
+#undef __
+
+}
+
+#define __ masm->
+
+void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp) {
+ Label filtered;
+ MacroAssembler* post_filter_masm = masm;
+
+ if (new_val == G0) return;
+
+ G1BarrierSet* bs = barrier_set_cast<G1BarrierSet>(BarrierSet::barrier_set());
+
+ if (G1RSBarrierRegionFilter) {
+ __ xor3(store_addr, new_val, tmp);
+ __ srlx(tmp, HeapRegion::LogOfHRGrainBytes, tmp);
+
+ __ cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
+ }
+
+ // If the "store_addr" register is an "in" or "local" register, move it to
+ // a scratch reg so we can pass it as an argument.
+ bool use_scr = !(store_addr->is_global() || store_addr->is_out());
+ // Pick a scratch register different from "tmp".
+ Register scr = (tmp == G1_scratch ? G3_scratch : G1_scratch);
+ // Make sure we use up the delay slot!
+ if (use_scr) {
+ post_filter_masm->mov(store_addr, scr);
+ } else {
+ post_filter_masm->nop();
+ }
+ __ save_frame(0);
+ __ call(dirty_card_log_enqueue);
+ if (use_scr) {
+ __ delayed()->mov(scr, O0);
+ } else {
+ __ delayed()->mov(store_addr->after_save(), O0);
+ }
+ __ restore();
+
+ __ bind(filtered);
+}
+
+void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register val, Address dst, Register tmp) {
+ bool in_heap = (decorators & IN_HEAP) != 0;
+ bool in_concurrent_root = (decorators & IN_CONCURRENT_ROOT) != 0;
+
+ bool needs_pre_barrier = in_heap || in_concurrent_root;
+ // No need for post barrier if storing NULL
+ bool needs_post_barrier = val != G0 && in_heap;
+
+ bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
+ bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
+ bool precise = on_array || on_anonymous;
+
+ Register index = dst.has_index() ? dst.index() : noreg;
+ int disp = dst.has_disp() ? dst.disp() : 0;
+
+ if (needs_pre_barrier) {
+ // Load and record the previous value.
+ g1_write_barrier_pre(masm, dst.base(), index, disp,
+ noreg /* pre_val */,
+ tmp, true /*preserve_o_regs*/);
+ }
+
+ Register new_val = val;
+ if (needs_post_barrier) {
+ // G1 barrier needs uncompressed oop for region cross check.
+ if (UseCompressedOops && val != G0) {
+ new_val = tmp;
+ __ mov(val, new_val);
+ }
+ }
+
+ BarrierSetAssembler::store_at(masm, decorators, type, val, dst, tmp);
+
+ if (needs_post_barrier) {
+ Register base = dst.base();
+ if (precise) {
+ if (!dst.has_index()) {
+ __ add(base, disp, base);
+ } else {
+ assert(!dst.has_disp(), "not supported yet");
+ __ add(base, index, base);
+ }
+ }
+ g1_write_barrier_post(masm, base, new_val, tmp);
+ }
+}
+
+void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address src, Register dst, Register tmp) {
+ bool on_oop = type == T_OBJECT || type == T_ARRAY;
+ bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
+ bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
+ bool on_reference = on_weak || on_phantom;
+ // Load the value of the referent field.
+ ModRefBarrierSetAssembler::load_at(masm, decorators, type, src, dst, tmp);
+ if (on_oop && on_reference) {
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer. Note with
+ // these parameters the pre-barrier does not generate
+ // the load of the previous value
+
+ Register pre_val = dst;
+ bool saved = false;
+ if (pre_val->is_in()) {
+ // The g1_write_barrier_pre method assumes that the pre_val
+ // is not in an input register.
+ __ save_frame_and_mov(0, pre_val, O0);
+ pre_val = O0;
+ saved = true;
+ }
+
+ g1_write_barrier_pre(masm, noreg /* obj */, noreg /* index */, 0 /* offset */,
+ pre_val /* pre_val */,
+ tmp /* tmp */,
+ true /* preserve_o_regs */);
+
+ if (saved) {
+ __ restore();
+ }
+ }
+}
+
+#undef __
+
+void G1BarrierSetAssembler::barrier_stubs_init() {
+ if (dirty_card_log_enqueue == 0) {
+ G1BarrierSet* bs = barrier_set_cast<G1BarrierSet>(BarrierSet::barrier_set());
+ CardTable *ct = bs->card_table();
+ generate_dirty_card_log_enqueue(ct->byte_map_base());
+ assert(dirty_card_log_enqueue != 0, "postcondition.");
+ }
+ if (satb_log_enqueue_with_frame == 0) {
+ generate_satb_log_enqueue(true);
+ assert(satb_log_enqueue_with_frame != 0, "postcondition.");
+ }
+ if (satb_log_enqueue_frameless == 0) {
+ generate_satb_log_enqueue(false);
+ assert(satb_log_enqueue_frameless != 0, "postcondition.");
+ }
+}
--- a/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/gc/g1/g1BarrierSetAssembler_sparc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,10 +30,19 @@
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
- virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count);
- virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count, Register tmp);
+ virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count);
+ virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp);
+
+ void g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register index, int offset, Register pre_val, Register tmp, bool preserve_o_regs);
+ void g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp);
+
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register val, Address dst, Register tmp);
+
+public:
+ virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address src, Register dst, Register tmp);
+ virtual void barrier_stubs_init();
};
#endif // CPU_SPARC_GC_G1_G1BARRIERSETASSEMBLER_SPARC_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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/shared/barrierSetAssembler.hpp"
+#include "interpreter/interp_masm.hpp"
+
+#define __ masm->
+
+void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register val, Address dst, Register tmp) {
+ bool on_heap = (decorators & IN_HEAP) != 0;
+ bool on_root = (decorators & IN_ROOT) != 0;
+ bool oop_not_null = (decorators & OOP_NOT_NULL) != 0;
+
+ switch (type) {
+ case T_ARRAY:
+ case T_OBJECT: {
+ if (on_heap) {
+ if (dst.has_disp() && !Assembler::is_simm13(dst.disp())) {
+ assert(!dst.has_index(), "not supported yet");
+ __ set(dst.disp(), tmp);
+ dst = Address(dst.base(), tmp);
+ }
+ if (UseCompressedOops) {
+ assert(dst.base() != val, "not enough registers");
+ if (oop_not_null) {
+ __ encode_heap_oop_not_null(val);
+ } else {
+ __ encode_heap_oop(val);
+ }
+ __ st(val, dst);
+ } else {
+ __ st_ptr(val, dst);
+ }
+ } else {
+ assert(on_root, "why else?");
+ __ st_ptr(val, dst);
+ }
+ break;
+ }
+ default: Unimplemented();
+ }
+}
+
+void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address src, Register dst, Register tmp) {
+ bool on_heap = (decorators & IN_HEAP) != 0;
+ bool on_root = (decorators & IN_ROOT) != 0;
+ bool oop_not_null = (decorators & OOP_NOT_NULL) != 0;
+
+ switch (type) {
+ case T_ARRAY:
+ case T_OBJECT: {
+ if (on_heap) {
+ if (src.has_disp() && !Assembler::is_simm13(src.disp())) {
+ assert(!src.has_index(), "not supported yet");
+ __ set(src.disp(), tmp);
+ src = Address(src.base(), tmp);
+ }
+ if (UseCompressedOops) {
+ __ lduw(src, dst);
+ if (oop_not_null) {
+ __ decode_heap_oop_not_null(dst);
+ } else {
+ __ decode_heap_oop(dst);
+ }
+ } else {
+ __ ld_ptr(src, dst);
+ }
+ } else {
+ assert(on_root, "why else?");
+ __ ld_ptr(src, dst);
+ }
+ break;
+ }
+ default: Unimplemented();
+ }
+}
--- a/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/gc/shared/barrierSetAssembler_sparc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -37,6 +37,14 @@
Register src, Register dst, Register count) {}
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register src, Register dst, Register count) {}
+
+ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register src, Address dst, Register tmp);
+
+ virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address src, Register dst, Register tmp);
+
+ virtual void barrier_stubs_init() {}
};
#endif // CPU_SPARC_GC_SHARED_BARRIERSETASSEMBLER_SPARC_HPP
--- a/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -29,7 +29,6 @@
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/cardTableBarrierSetAssembler.hpp"
-#include "gc/shared/collectedHeap.hpp"
#include "interpreter/interp_masm.hpp"
#define __ masm->
@@ -44,7 +43,7 @@
void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register tmp) {
- CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(Universe::heap()->barrier_set());
+ CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
CardTable* ct = ctbs->card_table();
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
assert_different_registers(addr, count, tmp);
@@ -70,3 +69,45 @@
__ BIND(L_done);
}
+
+void CardTableBarrierSetAssembler::card_table_write(MacroAssembler* masm,
+ jbyte* byte_map_base,
+ Register tmp, Register obj) {
+ __ srlx(obj, CardTable::card_shift, obj);
+ assert(tmp != obj, "need separate temp reg");
+ __ set((address) byte_map_base, tmp);
+ __ stb(G0, tmp, obj);
+}
+
+void CardTableBarrierSetAssembler::card_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp) {
+ // If we're writing constant NULL, we can skip the write barrier.
+ if (new_val == G0) return;
+ CardTableBarrierSet* bs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
+ card_table_write(masm, bs->card_table()->byte_map_base(), tmp, store_addr);
+}
+
+void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register val, Address dst, Register tmp) {
+ bool in_heap = (decorators & IN_HEAP) != 0;
+
+ bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
+ bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
+ bool precise = on_array || on_anonymous;
+
+ // No need for post barrier if storing NULL
+ bool needs_post_barrier = val != G0 && in_heap;
+
+ BarrierSetAssembler::store_at(masm, decorators, type, val, dst, tmp);
+ if (needs_post_barrier) {
+ Register base = dst.base();
+ if (precise) {
+ if (!dst.has_index()) {
+ __ add(base, dst.disp(), base);
+ } else {
+ assert(!dst.has_disp(), "not supported yet");
+ __ add(base, dst.index(), base);
+ }
+ }
+ card_write_barrier_post(masm, base, val, tmp);
+ }
+}
--- a/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/gc/shared/cardTableBarrierSetAssembler_sparc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -32,6 +32,13 @@
protected:
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register tmp);
+
+ void card_table_write(MacroAssembler* masm, jbyte* byte_map_base, Register tmp, Register obj);
+
+ void card_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, Register tmp);
+
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register val, Address dst, Register tmp);
};
#endif // CPU_SPARC_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_SPARC_HPP
--- a/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -55,3 +55,12 @@
}
}
}
+
+void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register val, Address dst, Register tmp) {
+ if (type == T_OBJECT || type == T_ARRAY) {
+ oop_store_at(masm, decorators, type, val, dst, tmp);
+ } else {
+ BarrierSetAssembler::store_at(masm, decorators, type, val, dst, tmp);
+ }
+}
--- a/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/gc/shared/modRefBarrierSetAssembler_sparc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,16 +28,27 @@
#include "asm/macroAssembler.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
+// The ModRefBarrierSetAssembler filters away accesses on BasicTypes other
+// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected
+// accesses, which are overridden in the concrete BarrierSetAssembler.
+
class ModRefBarrierSetAssembler: public BarrierSetAssembler {
protected:
- virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count) {}
- virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) {}
+ virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
+ Register addr, Register count) {}
+ virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
+ Register addr, Register count, Register tmp) {}
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register val, Address dst, Register tmp) = 0;
public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register src, Register dst, Register count);
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register src, Register dst, Register count);
+
+ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register val, Address dst, Register tmp);
};
#endif // CPU_SPARC_GC_SHARED_MODREFBARRIERSETASSEMBLER_SPARC_HPP
--- a/src/hotspot/cpu/sparc/interp_masm_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/interp_masm_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -753,7 +753,7 @@
resolve_oop_handle(result);
// Add in the index
add(result, tmp, result);
- load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result);
+ load_heap_oop(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT), result, tmp);
}
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -26,9 +26,9 @@
#include "jvm.h"
#include "asm/macroAssembler.inline.hpp"
#include "compiler/disassembler.hpp"
-#include "gc/shared/cardTable.hpp"
-#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
@@ -45,12 +45,6 @@
#include "runtime/stubRoutines.hpp"
#include "utilities/align.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
#ifdef COMPILER2
#include "opto/intrinsicnode.hpp"
#endif
@@ -174,6 +168,24 @@
return r;
}
+void MacroAssembler::resolve_jobject(Register value, Register tmp) {
+ Label done, not_weak;
+ br_null(value, false, Assembler::pn, done); // Use NULL as-is.
+ delayed()->andcc(value, JNIHandles::weak_tag_mask, G0); // Test for jweak
+ brx(Assembler::zero, true, Assembler::pt, not_weak);
+ delayed()->nop();
+ access_load_at(T_OBJECT, IN_ROOT | ON_PHANTOM_OOP_REF,
+ Address(value, -JNIHandles::weak_tag_value), value, tmp);
+ verify_oop(value);
+ br (Assembler::always, true, Assembler::pt, done);
+ delayed()->nop();
+ bind(not_weak);
+ access_load_at(T_OBJECT, IN_ROOT | IN_CONCURRENT_ROOT,
+ Address(value, 0), value, tmp);
+ verify_oop(value);
+ bind(done);
+}
+
void MacroAssembler::null_check(Register reg, int offset) {
if (needs_explicit_null_check((intptr_t)offset)) {
// provoke OS NULL exception if reg = NULL by
@@ -659,14 +671,6 @@
}
}
-void MacroAssembler::card_table_write(jbyte* byte_map_base,
- Register tmp, Register obj) {
- srlx(obj, CardTable::card_shift, obj);
- assert(tmp != obj, "need separate temp reg");
- set((address) byte_map_base, tmp);
- stb(G0, tmp, obj);
-}
-
void MacroAssembler::internal_sethi(const AddressLiteral& addrlit, Register d, bool ForceRelocatable) {
address save_pc;
@@ -3387,361 +3391,6 @@
bind(no_reserved_zone_enabling);
}
-
-///////////////////////////////////////////////////////////////////////////////////
-#if INCLUDE_ALL_GCS
-
-static address satb_log_enqueue_with_frame = NULL;
-static u_char* satb_log_enqueue_with_frame_end = NULL;
-
-static address satb_log_enqueue_frameless = NULL;
-static u_char* satb_log_enqueue_frameless_end = NULL;
-
-static int EnqueueCodeSize = 128 DEBUG_ONLY( + 256); // Instructions?
-
-static void generate_satb_log_enqueue(bool with_frame) {
- BufferBlob* bb = BufferBlob::create("enqueue_with_frame", EnqueueCodeSize);
- CodeBuffer buf(bb);
- MacroAssembler masm(&buf);
-
-#define __ masm.
-
- address start = __ pc();
- Register pre_val;
-
- Label refill, restart;
- if (with_frame) {
- __ save_frame(0);
- pre_val = I0; // Was O0 before the save.
- } else {
- pre_val = O0;
- }
-
- int satb_q_index_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_index());
-
- int satb_q_buf_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf());
-
- assert(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t) &&
- in_bytes(SATBMarkQueue::byte_width_of_buf()) == sizeof(intptr_t),
- "check sizes in assembly below");
-
- __ bind(restart);
-
- // Load the index into the SATB buffer. SATBMarkQueue::_index is a size_t
- // so ld_ptr is appropriate.
- __ ld_ptr(G2_thread, satb_q_index_byte_offset, L0);
-
- // index == 0?
- __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill);
-
- __ ld_ptr(G2_thread, satb_q_buf_byte_offset, L1);
- __ sub(L0, oopSize, L0);
-
- __ st_ptr(pre_val, L1, L0); // [_buf + index] := I0
- if (!with_frame) {
- // Use return-from-leaf
- __ retl();
- __ delayed()->st_ptr(L0, G2_thread, satb_q_index_byte_offset);
- } else {
- // Not delayed.
- __ st_ptr(L0, G2_thread, satb_q_index_byte_offset);
- }
- if (with_frame) {
- __ ret();
- __ delayed()->restore();
- }
- __ bind(refill);
-
- address handle_zero =
- CAST_FROM_FN_PTR(address,
- &SATBMarkQueueSet::handle_zero_index_for_thread);
- // This should be rare enough that we can afford to save all the
- // scratch registers that the calling context might be using.
- __ mov(G1_scratch, L0);
- __ mov(G3_scratch, L1);
- __ mov(G4, L2);
- // We need the value of O0 above (for the write into the buffer), so we
- // save and restore it.
- __ mov(O0, L3);
- // Since the call will overwrite O7, we save and restore that, as well.
- __ mov(O7, L4);
- __ call_VM_leaf(L5, handle_zero, G2_thread);
- __ mov(L0, G1_scratch);
- __ mov(L1, G3_scratch);
- __ mov(L2, G4);
- __ mov(L3, O0);
- __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
- __ delayed()->mov(L4, O7);
-
- if (with_frame) {
- satb_log_enqueue_with_frame = start;
- satb_log_enqueue_with_frame_end = __ pc();
- } else {
- satb_log_enqueue_frameless = start;
- satb_log_enqueue_frameless_end = __ pc();
- }
-
-#undef __
-}
-
-void MacroAssembler::g1_write_barrier_pre(Register obj,
- Register index,
- int offset,
- Register pre_val,
- Register tmp,
- bool preserve_o_regs) {
- Label filtered;
-
- if (obj == noreg) {
- // We are not loading the previous value so make
- // sure that we don't trash the value in pre_val
- // with the code below.
- assert_different_registers(pre_val, tmp);
- } else {
- // We will be loading the previous value
- // in this code so...
- assert(offset == 0 || index == noreg, "choose one");
- assert(pre_val == noreg, "check this code");
- }
-
- // Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- ld(G2,
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active()),
- tmp);
- } else {
- guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1,
- "Assumption");
- ldsb(G2,
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active()),
- tmp);
- }
-
- // Is marking active?
- cmp_and_br_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
-
- // Do we need to load the previous value?
- if (obj != noreg) {
- // Load the previous value...
- if (index == noreg) {
- if (Assembler::is_simm13(offset)) {
- load_heap_oop(obj, offset, tmp);
- } else {
- set(offset, tmp);
- load_heap_oop(obj, tmp, tmp);
- }
- } else {
- load_heap_oop(obj, index, tmp);
- }
- // Previous value has been loaded into tmp
- pre_val = tmp;
- }
-
- assert(pre_val != noreg, "must have a real register");
-
- // Is the previous value null?
- cmp_and_brx_short(pre_val, G0, Assembler::equal, Assembler::pt, filtered);
-
- // OK, it's not filtered, so we'll need to call enqueue. In the normal
- // case, pre_val will be a scratch G-reg, but there are some cases in
- // which it's an O-reg. In the first case, do a normal call. In the
- // latter, do a save here and call the frameless version.
-
- guarantee(pre_val->is_global() || pre_val->is_out(),
- "Or we need to think harder.");
-
- if (pre_val->is_global() && !preserve_o_regs) {
- call(satb_log_enqueue_with_frame);
- delayed()->mov(pre_val, O0);
- } else {
- save_frame(0);
- call(satb_log_enqueue_frameless);
- delayed()->mov(pre_val->after_save(), O0);
- restore();
- }
-
- bind(filtered);
-}
-
-static address dirty_card_log_enqueue = 0;
-static u_char* dirty_card_log_enqueue_end = 0;
-
-// This gets to assume that o0 contains the object address.
-static void generate_dirty_card_log_enqueue(jbyte* byte_map_base) {
- BufferBlob* bb = BufferBlob::create("dirty_card_enqueue", EnqueueCodeSize*2);
- CodeBuffer buf(bb);
- MacroAssembler masm(&buf);
-#define __ masm.
- address start = __ pc();
-
- Label not_already_dirty, restart, refill, young_card;
-
- __ srlx(O0, CardTable::card_shift, O0);
- AddressLiteral addrlit(byte_map_base);
- __ set(addrlit, O1); // O1 := <card table base>
- __ ldub(O0, O1, O2); // O2 := [O0 + O1]
-
- __ cmp_and_br_short(O2, G1CardTable::g1_young_card_val(), Assembler::equal, Assembler::pt, young_card);
-
- __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
- __ ldub(O0, O1, O2); // O2 := [O0 + O1]
-
- assert(CardTable::dirty_card_val() == 0, "otherwise check this code");
- __ cmp_and_br_short(O2, G0, Assembler::notEqual, Assembler::pt, not_already_dirty);
-
- __ bind(young_card);
- // We didn't take the branch, so we're already dirty: return.
- // Use return-from-leaf
- __ retl();
- __ delayed()->nop();
-
- // Not dirty.
- __ bind(not_already_dirty);
-
- // Get O0 + O1 into a reg by itself
- __ add(O0, O1, O3);
-
- // First, dirty it.
- __ stb(G0, O3, G0); // [cardPtr] := 0 (i.e., dirty).
-
- int dirty_card_q_index_byte_offset =
- in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_index());
- int dirty_card_q_buf_byte_offset =
- in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf());
- __ bind(restart);
-
- // Load the index into the update buffer. DirtyCardQueue::_index is
- // a size_t so ld_ptr is appropriate here.
- __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, L0);
-
- // index == 0?
- __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill);
-
- __ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, L1);
- __ sub(L0, oopSize, L0);
-
- __ st_ptr(O3, L1, L0); // [_buf + index] := I0
- // Use return-from-leaf
- __ retl();
- __ delayed()->st_ptr(L0, G2_thread, dirty_card_q_index_byte_offset);
-
- __ bind(refill);
- address handle_zero =
- CAST_FROM_FN_PTR(address,
- &DirtyCardQueueSet::handle_zero_index_for_thread);
- // This should be rare enough that we can afford to save all the
- // scratch registers that the calling context might be using.
- __ mov(G1_scratch, L3);
- __ mov(G3_scratch, L5);
- // We need the value of O3 above (for the write into the buffer), so we
- // save and restore it.
- __ mov(O3, L6);
- // Since the call will overwrite O7, we save and restore that, as well.
- __ mov(O7, L4);
-
- __ call_VM_leaf(L7_thread_cache, handle_zero, G2_thread);
- __ mov(L3, G1_scratch);
- __ mov(L5, G3_scratch);
- __ mov(L6, O3);
- __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
- __ delayed()->mov(L4, O7);
-
- dirty_card_log_enqueue = start;
- dirty_card_log_enqueue_end = __ pc();
- // XXX Should have a guarantee here about not going off the end!
- // Does it already do so? Do an experiment...
-
-#undef __
-
-}
-
-void MacroAssembler::g1_write_barrier_post(Register store_addr, Register new_val, Register tmp) {
-
- Label filtered;
- MacroAssembler* post_filter_masm = this;
-
- if (new_val == G0) return;
-
- G1BarrierSet* bs =
- barrier_set_cast<G1BarrierSet>(Universe::heap()->barrier_set());
- CardTable* ct = bs->card_table();
-
- if (G1RSBarrierRegionFilter) {
- xor3(store_addr, new_val, tmp);
- srlx(tmp, HeapRegion::LogOfHRGrainBytes, tmp);
-
- // XXX Should I predict this taken or not? Does it matter?
- cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
- }
-
- // If the "store_addr" register is an "in" or "local" register, move it to
- // a scratch reg so we can pass it as an argument.
- bool use_scr = !(store_addr->is_global() || store_addr->is_out());
- // Pick a scratch register different from "tmp".
- Register scr = (tmp == G1_scratch ? G3_scratch : G1_scratch);
- // Make sure we use up the delay slot!
- if (use_scr) {
- post_filter_masm->mov(store_addr, scr);
- } else {
- post_filter_masm->nop();
- }
- save_frame(0);
- call(dirty_card_log_enqueue);
- if (use_scr) {
- delayed()->mov(scr, O0);
- } else {
- delayed()->mov(store_addr->after_save(), O0);
- }
- restore();
-
- bind(filtered);
-}
-
-// Called from init_globals() after universe_init() and before interpreter_init()
-void g1_barrier_stubs_init() {
- CollectedHeap* heap = Universe::heap();
- if (heap->kind() == CollectedHeap::G1) {
- // Only needed for G1
- if (dirty_card_log_enqueue == 0) {
- G1BarrierSet* bs =
- barrier_set_cast<G1BarrierSet>(heap->barrier_set());
- CardTable *ct = bs->card_table();
- generate_dirty_card_log_enqueue(ct->byte_map_base());
- assert(dirty_card_log_enqueue != 0, "postcondition.");
- }
- if (satb_log_enqueue_with_frame == 0) {
- generate_satb_log_enqueue(true);
- assert(satb_log_enqueue_with_frame != 0, "postcondition.");
- }
- if (satb_log_enqueue_frameless == 0) {
- generate_satb_log_enqueue(false);
- assert(satb_log_enqueue_frameless != 0, "postcondition.");
- }
- }
-}
-
-#endif // INCLUDE_ALL_GCS
-///////////////////////////////////////////////////////////////////////////////////
-
-void MacroAssembler::card_write_barrier_post(Register store_addr, Register new_val, Register tmp) {
- // If we're writing constant NULL, we can skip the write barrier.
- if (new_val == G0) return;
- CardTableBarrierSet* bs =
- barrier_set_cast<CardTableBarrierSet>(Universe::heap()->barrier_set());
- CardTable* ct = bs->card_table();
-
- assert(bs->kind() == BarrierSet::CardTableBarrierSet, "wrong barrier");
- card_table_write(ct->byte_map_base(), tmp, store_addr);
-}
-
// ((OopHandle)result).resolve();
void MacroAssembler::resolve_oop_handle(Register result) {
// OopHandle::resolve is an indirection.
@@ -3786,65 +3435,63 @@
}
}
-void MacroAssembler::load_heap_oop(const Address& s, Register d) {
- if (UseCompressedOops) {
- lduw(s, d);
- decode_heap_oop(d);
+void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators,
+ Register src, Address dst, Register tmp) {
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bool as_raw = (decorators & AS_RAW) != 0;
+ if (as_raw) {
+ bs->BarrierSetAssembler::store_at(this, decorators, type, src, dst, tmp);
} else {
- ld_ptr(s, d);
+ bs->store_at(this, decorators, type, src, dst, tmp);
}
}
-void MacroAssembler::load_heap_oop(Register s1, Register s2, Register d) {
- if (UseCompressedOops) {
- lduw(s1, s2, d);
- decode_heap_oop(d, d);
+void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators,
+ Address src, Register dst, Register tmp) {
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bool as_raw = (decorators & AS_RAW) != 0;
+ if (as_raw) {
+ bs->BarrierSetAssembler::load_at(this, decorators, type, src, dst, tmp);
} else {
- ld_ptr(s1, s2, d);
- }
-}
-
-void MacroAssembler::load_heap_oop(Register s1, int simm13a, Register d) {
- if (UseCompressedOops) {
- lduw(s1, simm13a, d);
- decode_heap_oop(d, d);
- } else {
- ld_ptr(s1, simm13a, d);
+ bs->load_at(this, decorators, type, src, dst, tmp);
}
}
-void MacroAssembler::load_heap_oop(Register s1, RegisterOrConstant s2, Register d) {
- if (s2.is_constant()) load_heap_oop(s1, s2.as_constant(), d);
- else load_heap_oop(s1, s2.as_register(), d);
+void MacroAssembler::load_heap_oop(const Address& s, Register d, Register tmp, DecoratorSet decorators) {
+ access_load_at(T_OBJECT, IN_HEAP | decorators, s, d, tmp);
+}
+
+void MacroAssembler::load_heap_oop(Register s1, Register s2, Register d, Register tmp, DecoratorSet decorators) {
+ access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, s2), d, tmp);
}
-void MacroAssembler::store_heap_oop(Register d, Register s1, Register s2) {
- if (UseCompressedOops) {
- assert(s1 != d && s2 != d, "not enough registers");
- encode_heap_oop(d);
- st(d, s1, s2);
+void MacroAssembler::load_heap_oop(Register s1, int simm13a, Register d, Register tmp, DecoratorSet decorators) {
+ access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, simm13a), d, tmp);
+}
+
+void MacroAssembler::load_heap_oop(Register s1, RegisterOrConstant s2, Register d, Register tmp, DecoratorSet decorators) {
+ if (s2.is_constant()) {
+ access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, s2.as_constant()), d, tmp);
} else {
- st_ptr(d, s1, s2);
+ access_load_at(T_OBJECT, IN_HEAP | decorators, Address(s1, s2.as_register()), d, tmp);
}
}
-void MacroAssembler::store_heap_oop(Register d, Register s1, int simm13a) {
- if (UseCompressedOops) {
- assert(s1 != d, "not enough registers");
- encode_heap_oop(d);
- st(d, s1, simm13a);
- } else {
- st_ptr(d, s1, simm13a);
- }
+void MacroAssembler::store_heap_oop(Register d, Register s1, Register s2, Register tmp, DecoratorSet decorators) {
+ access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(s1, s2), tmp);
+}
+
+void MacroAssembler::store_heap_oop(Register d, Register s1, int simm13a, Register tmp, DecoratorSet decorators) {
+ access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(s1, simm13a), tmp);
}
-void MacroAssembler::store_heap_oop(Register d, const Address& a, int offset) {
- if (UseCompressedOops) {
- assert(a.base() != d, "not enough registers");
- encode_heap_oop(d);
- st(d, a, offset);
+void MacroAssembler::store_heap_oop(Register d, const Address& a, int offset, Register tmp, DecoratorSet decorators) {
+ if (a.has_index()) {
+ assert(!a.has_disp(), "not supported yet");
+ assert(offset == 0, "not supported yet");
+ access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(a.base(), a.index()), tmp);
} else {
- st_ptr(d, a, offset);
+ access_store_at(T_OBJECT, IN_HEAP | decorators, d, Address(a.base(), a.disp() + offset), tmp);
}
}
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -703,6 +703,9 @@
// cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's
inline void cas_ptr( Register s1, Register s2, Register d);
+ // Resolve a jobject or jweak
+ void resolve_jobject(Register value, Register tmp);
+
// Functions for isolating 64 bit shifts for LP64
inline void sll_ptr( Register s1, Register s2, Register d );
inline void sll_ptr( Register s1, int imm6a, Register d );
@@ -974,13 +977,25 @@
void store_klass_gap(Register s, Register dst_oop);
// oop manipulations
- void load_heap_oop(const Address& s, Register d);
- void load_heap_oop(Register s1, Register s2, Register d);
- void load_heap_oop(Register s1, int simm13a, Register d);
- void load_heap_oop(Register s1, RegisterOrConstant s2, Register d);
- void store_heap_oop(Register d, Register s1, Register s2);
- void store_heap_oop(Register d, Register s1, int simm13a);
- void store_heap_oop(Register d, const Address& a, int offset = 0);
+ void access_store_at(BasicType type, DecoratorSet decorators,
+ Register src, Address dst, Register tmp);
+ void access_load_at(BasicType type, DecoratorSet decorators,
+ Address src, Register dst, Register tmp);
+
+ void load_heap_oop(const Address& s, Register d,
+ Register tmp = noreg, DecoratorSet decorators = 0);
+ void load_heap_oop(Register s1, Register s2, Register d,
+ Register tmp = noreg, DecoratorSet decorators = 0);
+ void load_heap_oop(Register s1, int simm13a, Register d,
+ Register tmp = noreg, DecoratorSet decorators = 0);
+ void load_heap_oop(Register s1, RegisterOrConstant s2, Register d,
+ Register tmp = noreg, DecoratorSet decorators = 0);
+ void store_heap_oop(Register d, Register s1, Register s2,
+ Register tmp = noreg, DecoratorSet decorators = 0);
+ void store_heap_oop(Register d, Register s1, int simm13a,
+ Register tmp = noreg, DecoratorSet decorators = 0);
+ void store_heap_oop(Register d, const Address& a, int offset = 0,
+ Register tmp = noreg, DecoratorSet decorators = 0);
void encode_heap_oop(Register src, Register dst);
void encode_heap_oop(Register r) {
@@ -1043,19 +1058,6 @@
// check_and_forward_exception to handle exceptions when it is safe
void check_and_forward_exception(Register scratch_reg);
- // Write to card table for - register is destroyed afterwards.
- void card_table_write(jbyte* byte_map_base, Register tmp, Register obj);
-
- void card_write_barrier_post(Register store_addr, Register new_val, Register tmp);
-
-#if INCLUDE_ALL_GCS
- // General G1 pre-barrier generator.
- void g1_write_barrier_pre(Register obj, Register index, int offset, Register pre_val, Register tmp, bool preserve_o_regs);
-
- // General G1 post-barrier generator
- void g1_write_barrier_post(Register store_addr, Register new_val, Register tmp);
-#endif // INCLUDE_ALL_GCS
-
// pushes double TOS element of FPU stack on CPU stack; pops from FPU stack
void push_fTOS();
--- a/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -31,8 +31,6 @@
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-
// An implementation of memset, for use when there may be concurrent
// readers of the region being stored into.
//
@@ -156,5 +154,3 @@
// Fill any partial word suffix. Also the prefix if size < BytesPerWord.
fill_subword(to, end, value);
}
-
-#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/cpu/sparc/methodHandles_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/methodHandles_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -180,13 +180,13 @@
// Load the invoker, as MH -> MH.form -> LF.vmentry
__ verify_oop(recv);
- __ load_heap_oop(Address(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes())), method_temp);
+ __ load_heap_oop(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes()), method_temp, temp2);
__ verify_oop(method_temp);
- __ load_heap_oop(Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes())), method_temp);
+ __ load_heap_oop(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes()), method_temp, temp2);
__ verify_oop(method_temp);
- __ load_heap_oop(Address(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes())), method_temp);
+ __ load_heap_oop(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes()), method_temp, temp2);
__ verify_oop(method_temp);
- __ ld_ptr( Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())), method_temp);
+ __ ld_ptr(Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())), method_temp);
if (VerifyMethodHandles && !for_compiler_entry) {
// make sure recv is already on stack
@@ -362,7 +362,7 @@
if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) {
Label L_ok;
Register temp2_defc = temp2;
- __ load_heap_oop(member_clazz, temp2_defc);
+ __ load_heap_oop(member_clazz, temp2_defc, temp3);
load_klass_from_Class(_masm, temp2_defc, temp3, temp4);
__ verify_klass_ptr(temp2_defc);
__ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, temp4, L_ok);
@@ -389,7 +389,7 @@
if (VerifyMethodHandles) {
verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp2);
}
- __ load_heap_oop(member_vmtarget, G5_method);
+ __ load_heap_oop(member_vmtarget, G5_method, temp3);
__ ld_ptr(vmtarget_method, G5_method);
break;
@@ -397,7 +397,7 @@
if (VerifyMethodHandles) {
verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp2);
}
- __ load_heap_oop(member_vmtarget, G5_method);
+ __ load_heap_oop(member_vmtarget, G5_method, temp3);
__ ld_ptr(vmtarget_method, G5_method);
break;
@@ -438,7 +438,7 @@
}
Register temp2_intf = temp2;
- __ load_heap_oop(member_clazz, temp2_intf);
+ __ load_heap_oop(member_clazz, temp2_intf, temp3);
load_klass_from_Class(_masm, temp2_intf, temp3, temp4);
__ verify_klass_ptr(temp2_intf);
--- a/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/sharedRuntime_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -2516,28 +2516,7 @@
// Unbox oop result, e.g. JNIHandles::resolve value in I0.
if (ret_type == T_OBJECT || ret_type == T_ARRAY) {
- Label done, not_weak;
- __ br_null(I0, false, Assembler::pn, done); // Use NULL as-is.
- __ delayed()->andcc(I0, JNIHandles::weak_tag_mask, G0); // Test for jweak
- __ brx(Assembler::zero, true, Assembler::pt, not_weak);
- __ delayed()->ld_ptr(I0, 0, I0); // Maybe resolve (untagged) jobject.
- // Resolve jweak.
- __ ld_ptr(I0, -JNIHandles::weak_tag_value, I0);
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- // Copy to O0 because macro doesn't allow pre_val in input reg.
- __ mov(I0, O0);
- __ g1_write_barrier_pre(noreg /* obj */,
- noreg /* index */,
- 0 /* offset */,
- O0 /* pre_val */,
- G3_scratch /* tmp */,
- true /* preserve_o_regs */);
- }
-#endif // INCLUDE_ALL_GCS
- __ bind(not_weak);
- __ verify_oop(I0);
- __ bind(done);
+ __ resolve_jobject(I0, G3_scratch);
}
if (CheckJNICalls) {
--- a/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -2277,7 +2277,7 @@
decorators |= ARRAYCOPY_ALIGNED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, T_OBJECT, from, to, count);
assert_clean_int(count, O3); // Make sure 'count' is clean int.
@@ -2334,7 +2334,7 @@
decorators |= ARRAYCOPY_ALIGNED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, T_OBJECT, from, to, count);
if (UseCompressedOops) {
@@ -2451,7 +2451,7 @@
decorators |= AS_DEST_NOT_INITIALIZED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, T_OBJECT, O0_from, O1_to, O2_count);
Label load_element, store_element, do_epilogue, fail, done;
@@ -2474,14 +2474,14 @@
__ BIND(store_element);
__ deccc(G1_remain); // decrement the count
- __ store_heap_oop(G3_oop, O1_to, O5_offset); // store the oop
+ __ store_heap_oop(G3_oop, O1_to, O5_offset, noreg, AS_RAW); // store the oop
__ inc(O5_offset, heapOopSize); // step to next offset
__ brx(Assembler::zero, true, Assembler::pt, do_epilogue);
__ delayed()->set(0, O0); // return -1 on success
// ======== loop entry is here ========
__ BIND(load_element);
- __ load_heap_oop(O0_from, O5_offset, G3_oop); // load the oop
+ __ load_heap_oop(O0_from, O5_offset, G3_oop, noreg, AS_RAW); // load the oop
__ br_null_short(G3_oop, Assembler::pt, store_element);
__ load_klass(G3_oop, G4_klass); // query the object klass
--- a/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/templateInterpreterGenerator_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,6 +24,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
@@ -827,29 +828,18 @@
// Method entry for java.lang.ref.Reference.get.
address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
-#if INCLUDE_ALL_GCS
// Code: _aload_0, _getfield, _areturn
// parameter size = 1
//
// The code that gets generated by this routine is split into 2 parts:
- // 1. The "intrinsified" code for G1 (or any SATB based GC),
+ // 1. The "intrinsified" code performing an ON_WEAK_OOP_REF load,
// 2. The slow path - which is an expansion of the regular method entry.
//
// Notes:-
- // * In the G1 code we do not check whether we need to block for
- // a safepoint. If G1 is enabled then we must execute the specialized
- // code for Reference.get (except when the Reference object is null)
- // so that we can log the value in the referent field with an SATB
- // update buffer.
- // If the code for the getfield template is modified so that the
- // G1 pre-barrier code is executed when the current method is
- // Reference.get() then going through the normal method entry
- // will be fine.
- // * The G1 code can, however, check the receiver object (the instance
- // of java.lang.Reference) and jump to the slow path if null. If the
- // Reference object is null then we obviously cannot fetch the referent
- // and so we don't need to call the G1 pre-barrier. Thus we can use the
- // regular method entry code to generate the NPE.
+ // * An intrinsic is always executed, where an ON_WEAK_OOP_REF load is performed.
+ // * We may jump to the slow path iff the receiver is null. If the
+ // Reference object is null then we no longer perform an ON_WEAK_OOP_REF load
+ // Thus we can use the regular method entry code to generate the NPE.
//
// This code is based on generate_accessor_enty.
@@ -858,51 +848,27 @@
const int referent_offset = java_lang_ref_Reference::referent_offset;
guarantee(referent_offset > 0, "referent offset not initialized");
- if (UseG1GC) {
- Label slow_path;
+ Label slow_path;
- // In the G1 code we don't check if we need to reach a safepoint. We
- // continue and the thread will safepoint at the next bytecode dispatch.
+ // In the G1 code we don't check if we need to reach a safepoint. We
+ // continue and the thread will safepoint at the next bytecode dispatch.
- // Check if local 0 != NULL
- // If the receiver is null then it is OK to jump to the slow path.
- __ ld_ptr(Gargs, G0, Otos_i ); // get local 0
- // check if local 0 == NULL and go the slow path
- __ cmp_and_brx_short(Otos_i, 0, Assembler::equal, Assembler::pn, slow_path);
-
-
- // Load the value of the referent field.
- if (Assembler::is_simm13(referent_offset)) {
- __ load_heap_oop(Otos_i, referent_offset, Otos_i);
- } else {
- __ set(referent_offset, G3_scratch);
- __ load_heap_oop(Otos_i, G3_scratch, Otos_i);
- }
+ // Check if local 0 != NULL
+ // If the receiver is null then it is OK to jump to the slow path.
+ __ ld_ptr(Gargs, G0, Otos_i ); // get local 0
+ // check if local 0 == NULL and go the slow path
+ __ cmp_and_brx_short(Otos_i, 0, Assembler::equal, Assembler::pn, slow_path);
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer. Note with
- // these parameters the pre-barrier does not generate
- // the load of the previous value
-
- __ g1_write_barrier_pre(noreg /* obj */, noreg /* index */, 0 /* offset */,
- Otos_i /* pre_val */,
- G3_scratch /* tmp */,
- true /* preserve_o_regs */);
+ __ load_heap_oop(Otos_i, referent_offset, Otos_i, G3_scratch, ON_WEAK_OOP_REF);
- // _areturn
- __ retl(); // return from leaf routine
- __ delayed()->mov(O5_savedSP, SP);
+ // _areturn
+ __ retl(); // return from leaf routine
+ __ delayed()->mov(O5_savedSP, SP);
- // Generate regular method entry
- __ bind(slow_path);
- __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
- return entry;
- }
-#endif // INCLUDE_ALL_GCS
-
- // If G1 is not enabled then attempt to go through the accessor entry point
- // Reference.get is an accessor
- return NULL;
+ // Generate regular method entry
+ __ bind(slow_path);
+ __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
+ return entry;
}
/**
@@ -1469,33 +1435,15 @@
// If we have an oop result store it where it will be safe for any further gc
// until we return now that we've released the handle it might be protected by
- { Label no_oop, store_result;
+ { Label no_oop;
__ set((intptr_t)AbstractInterpreter::result_handler(T_OBJECT), G3_scratch);
__ cmp_and_brx_short(G3_scratch, Lscratch, Assembler::notEqual, Assembler::pt, no_oop);
- // Unbox oop result, e.g. JNIHandles::resolve value in O0.
- __ br_null(O0, false, Assembler::pn, store_result); // Use NULL as-is.
- __ delayed()->andcc(O0, JNIHandles::weak_tag_mask, G0); // Test for jweak
- __ brx(Assembler::zero, true, Assembler::pt, store_result);
- __ delayed()->ld_ptr(O0, 0, O0); // Maybe resolve (untagged) jobject.
- // Resolve jweak.
- __ ld_ptr(O0, -JNIHandles::weak_tag_value, O0);
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- __ g1_write_barrier_pre(noreg /* obj */,
- noreg /* index */,
- 0 /* offset */,
- O0 /* pre_val */,
- G3_scratch /* tmp */,
- true /* preserve_o_regs */);
- }
-#endif // INCLUDE_ALL_GCS
- __ bind(store_result);
+ __ resolve_jobject(O0, G3_scratch);
// Store it where gc will look for it and result handler expects it.
__ st_ptr(O0, FP, (frame::interpreter_frame_oop_temp_offset*wordSize) + STACK_BIAS);
__ bind(no_oop);
-
}
--- a/src/hotspot/cpu/sparc/templateTable_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/sparc/templateTable_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/interp_masm.hpp"
@@ -51,74 +52,31 @@
int offset,
Register val,
Register tmp,
- BarrierSet::Name barrier,
- bool precise) {
+ DecoratorSet decorators = 0) {
assert(tmp != val && tmp != base && tmp != index, "register collision");
assert(index == noreg || offset == 0, "only one offset");
- switch (barrier) {
-#if INCLUDE_ALL_GCS
- case BarrierSet::G1BarrierSet:
- {
- // Load and record the previous value.
- __ g1_write_barrier_pre(base, index, offset,
- noreg /* pre_val */,
- tmp, true /*preserve_o_regs*/);
-
- // G1 barrier needs uncompressed oop for region cross check.
- Register new_val = val;
- if (UseCompressedOops && val != G0) {
- new_val = tmp;
- __ mov(val, new_val);
- }
-
- if (index == noreg ) {
- assert(Assembler::is_simm13(offset), "fix this code");
- __ store_heap_oop(val, base, offset);
- } else {
- __ store_heap_oop(val, base, index);
- }
-
- // No need for post barrier if storing NULL
- if (val != G0) {
- if (precise) {
- if (index == noreg) {
- __ add(base, offset, base);
- } else {
- __ add(base, index, base);
- }
- }
- __ g1_write_barrier_post(base, new_val, tmp);
- }
- }
- break;
-#endif // INCLUDE_ALL_GCS
- case BarrierSet::CardTableBarrierSet:
- {
- if (index == noreg ) {
- assert(Assembler::is_simm13(offset), "fix this code");
- __ store_heap_oop(val, base, offset);
- } else {
- __ store_heap_oop(val, base, index);
- }
- // No need for post barrier if storing NULL
- if (val != G0) {
- if (precise) {
- if (index == noreg) {
- __ add(base, offset, base);
- } else {
- __ add(base, index, base);
- }
- }
- __ card_write_barrier_post(base, val, tmp);
- }
- }
- break;
- case BarrierSet::ModRef:
- ShouldNotReachHere();
- break;
- default :
- ShouldNotReachHere();
-
+ if (index == noreg) {
+ __ store_heap_oop(val, base, offset, tmp, decorators);
+ } else {
+ __ store_heap_oop(val, base, index, tmp, decorators);
+ }
+}
+
+// Do an oop load like val = *(base + index + offset)
+// index can be noreg.
+static void do_oop_load(InterpreterMacroAssembler* _masm,
+ Register base,
+ Register index,
+ int offset,
+ Register dst,
+ Register tmp,
+ DecoratorSet decorators = 0) {
+ assert(tmp != dst && tmp != base && tmp != index, "register collision");
+ assert(index == noreg || offset == 0, "only one offset");
+ if (index == noreg) {
+ __ load_heap_oop(base, offset, dst, tmp, decorators);
+ } else {
+ __ load_heap_oop(base, index, dst, tmp, decorators);
}
}
@@ -587,7 +545,13 @@
// Otos_i: index
// tos: array
__ index_check(O2, Otos_i, UseCompressedOops ? 2 : LogBytesPerWord, G3_scratch, O3);
- __ load_heap_oop(O3, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Otos_i);
+ do_oop_load(_masm,
+ O3,
+ noreg,
+ arrayOopDesc::base_offset_in_bytes(T_OBJECT),
+ Otos_i,
+ G3_scratch,
+ IN_HEAP_ARRAY);
__ verify_oop(Otos_i);
}
@@ -887,13 +851,13 @@
// Store is OK.
__ bind(store_ok);
- do_oop_store(_masm, O1, noreg, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Otos_i, G3_scratch, _bs->kind(), true);
+ do_oop_store(_masm, O1, noreg, arrayOopDesc::base_offset_in_bytes(T_OBJECT), Otos_i, G3_scratch, IN_HEAP_ARRAY);
__ ba(done);
__ delayed()->inc(Lesp, 3* Interpreter::stackElementSize); // adj sp (pops array, index and value)
__ bind(is_null);
- do_oop_store(_masm, O1, noreg, arrayOopDesc::base_offset_in_bytes(T_OBJECT), G0, G4_scratch, _bs->kind(), true);
+ do_oop_store(_masm, O1, noreg, arrayOopDesc::base_offset_in_bytes(T_OBJECT), G0, G4_scratch, IN_HEAP_ARRAY);
__ profile_null_seen(G3_scratch);
__ inc(Lesp, 3* Interpreter::stackElementSize); // adj sp (pops array, index and value)
@@ -2155,7 +2119,7 @@
__ delayed() ->cmp(Rflags, itos);
// atos
- __ load_heap_oop(Rclass, Roffset, Otos_i);
+ do_oop_load(_masm, Rclass, Roffset, 0, Otos_i, noreg);
__ verify_oop(Otos_i);
__ push(atos);
if (!is_static && rc == may_rewrite) {
@@ -2354,7 +2318,7 @@
__ ldf(FloatRegisterImpl::D, Otos_i, Roffset, Ftos_d);
break;
case Bytecodes::_fast_agetfield:
- __ load_heap_oop(Otos_i, Roffset, Otos_i);
+ do_oop_load(_masm, Otos_i, Roffset, 0, Otos_i, noreg);
break;
default:
ShouldNotReachHere();
@@ -2537,7 +2501,7 @@
{
__ pop_ptr();
__ verify_oop(Otos_i);
- do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch, _bs->kind(), false);
+ do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch);
__ ba(checkVolatile);
__ delayed()->tst(Lscratch);
}
@@ -2582,7 +2546,7 @@
__ pop_ptr();
pop_and_check_object(Rclass);
__ verify_oop(Otos_i);
- do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch, _bs->kind(), false);
+ do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch);
if (rc == may_rewrite) patch_bytecode(Bytecodes::_fast_aputfield, G3_scratch, G4_scratch, true, byte_no);
__ ba(checkVolatile);
__ delayed()->tst(Lscratch);
@@ -2763,7 +2727,7 @@
__ stf(FloatRegisterImpl::D, Ftos_d, Rclass, Roffset);
break;
case Bytecodes::_fast_aputfield:
- do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch, _bs->kind(), false);
+ do_oop_store(_masm, Rclass, Roffset, 0, Otos_i, G1_scratch);
break;
default:
ShouldNotReachHere();
@@ -2805,7 +2769,7 @@
__ verify_oop(Rreceiver);
__ null_check(Rreceiver);
if (state == atos) {
- __ load_heap_oop(Rreceiver, Roffset, Otos_i);
+ do_oop_load(_masm, Rreceiver, Roffset, 0, Otos_i, noreg);
} else if (state == itos) {
__ ld (Rreceiver, Roffset, Otos_i) ;
} else if (state == ftos) {
--- a/src/hotspot/cpu/x86/assembler_x86.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/assembler_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -38,7 +38,6 @@
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/heapRegion.hpp"
#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,6 +44,7 @@
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#endif
@@ -1562,7 +1563,7 @@
StubFrame f(sasm, "g1_pre_barrier", dont_gc_arguments);
// arg0 : previous value of memory
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ movptr(rax, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax);
@@ -1578,12 +1579,9 @@
NOT_LP64(__ get_thread(thread);)
- Address queue_active(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active()));
- Address queue_index(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_index()));
- Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf()));
+ Address queue_active(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+ Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
+ Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
Label done;
Label runtime;
@@ -1632,7 +1630,7 @@
{
StubFrame f(sasm, "g1_post_barrier", dont_gc_arguments);
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->kind() != BarrierSet::G1BarrierSet) {
__ movptr(rax, (int)id);
__ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), rax);
@@ -1652,10 +1650,8 @@
const Register thread = NOT_LP64(rax) LP64_ONLY(r15_thread);
- Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_index()));
- Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf()));
+ Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
+ Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
__ push(rax);
__ push(rcx);
--- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -27,11 +27,10 @@
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1CardTable.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
-#include "gc/shared/collectedHeap.hpp"
#include "interpreter/interp_masm.hpp"
#include "runtime/sharedRuntime.hpp"
-#include "runtime/thread.hpp"
#include "utilities/macros.hpp"
#define __ masm->
@@ -48,8 +47,7 @@
#endif
Label filtered;
- Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active()));
+ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
// Is marking active?
if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
__ cmpl(in_progress, 0);
@@ -111,3 +109,293 @@
#endif
__ popa();
}
+
+void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register dst, Address src, Register tmp1, Register tmp_thread) {
+ bool on_oop = type == T_OBJECT || type == T_ARRAY;
+ bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
+ bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
+ bool on_reference = on_weak || on_phantom;
+ ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread);
+ if (on_oop && on_reference) {
+ const Register thread = NOT_LP64(tmp_thread) LP64_ONLY(r15_thread);
+ NOT_LP64(__ get_thread(thread));
+
+ // Generate the G1 pre-barrier code to log the value of
+ // the referent field in an SATB buffer.
+ g1_write_barrier_pre(masm /* masm */,
+ noreg /* obj */,
+ dst /* pre_val */,
+ thread /* thread */,
+ tmp1 /* tmp */,
+ true /* tosca_live */,
+ true /* expand_call */);
+ }
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp,
+ bool tosca_live,
+ bool expand_call) {
+ // If expand_call is true then we expand the call_VM_leaf macro
+ // directly to skip generating the check by
+ // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
+
+#ifdef _LP64
+ assert(thread == r15_thread, "must be");
+#endif // _LP64
+
+ Label done;
+ Label runtime;
+
+ assert(pre_val != noreg, "check this code");
+
+ if (obj != noreg) {
+ assert_different_registers(obj, pre_val, tmp);
+ assert(pre_val != rax, "check this code");
+ }
+
+ Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+ Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
+ Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
+
+ // Is marking active?
+ if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
+ __ cmpl(in_progress, 0);
+ } else {
+ assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
+ __ cmpb(in_progress, 0);
+ }
+ __ jcc(Assembler::equal, done);
+
+ // Do we need to load the previous value?
+ if (obj != noreg) {
+ __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW);
+ }
+
+ // Is the previous value null?
+ __ cmpptr(pre_val, (int32_t) NULL_WORD);
+ __ jcc(Assembler::equal, done);
+
+ // Can we store original value in the thread's buffer?
+ // Is index == 0?
+ // (The index field is typed as size_t.)
+
+ __ movptr(tmp, index); // tmp := *index_adr
+ __ cmpptr(tmp, 0); // tmp == 0?
+ __ jcc(Assembler::equal, runtime); // If yes, goto runtime
+
+ __ subptr(tmp, wordSize); // tmp := tmp - wordSize
+ __ movptr(index, tmp); // *index_adr := tmp
+ __ addptr(tmp, buffer); // tmp := tmp + *buffer_adr
+
+ // Record the previous value
+ __ movptr(Address(tmp, 0), pre_val);
+ __ jmp(done);
+
+ __ bind(runtime);
+ // save the live input values
+ if(tosca_live) __ push(rax);
+
+ if (obj != noreg && obj != rax)
+ __ push(obj);
+
+ if (pre_val != rax)
+ __ push(pre_val);
+
+ // Calling the runtime using the regular call_VM_leaf mechanism generates
+ // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
+ // that checks that the *(ebp+frame::interpreter_frame_last_sp) == NULL.
+ //
+ // If we care generating the pre-barrier without a frame (e.g. in the
+ // intrinsified Reference.get() routine) then ebp might be pointing to
+ // the caller frame and so this check will most likely fail at runtime.
+ //
+ // Expanding the call directly bypasses the generation of the check.
+ // So when we do not have have a full interpreter frame on the stack
+ // expand_call should be passed true.
+
+ NOT_LP64( __ push(thread); )
+
+ if (expand_call) {
+ LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); )
+#ifdef _LP64
+ if (c_rarg1 != thread) {
+ __ mov(c_rarg1, thread);
+ }
+ if (c_rarg0 != pre_val) {
+ __ mov(c_rarg0, pre_val);
+ }
+#else
+ __ push(thread);
+ __ push(pre_val);
+#endif
+ __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), 2);
+ } else {
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
+ }
+
+ NOT_LP64( __ pop(thread); )
+
+ // save the live input values
+ if (pre_val != rax)
+ __ pop(pre_val);
+
+ if (obj != noreg && obj != rax)
+ __ pop(obj);
+
+ if(tosca_live) __ pop(rax);
+
+ __ bind(done);
+}
+
+void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp,
+ Register tmp2) {
+#ifdef _LP64
+ assert(thread == r15_thread, "must be");
+#endif // _LP64
+
+ Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
+ Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
+
+ CardTableBarrierSet* ct =
+ barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
+ assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code");
+
+ Label done;
+ Label runtime;
+
+ // Does store cross heap regions?
+
+ __ movptr(tmp, store_addr);
+ __ xorptr(tmp, new_val);
+ __ shrptr(tmp, HeapRegion::LogOfHRGrainBytes);
+ __ jcc(Assembler::equal, done);
+
+ // crosses regions, storing NULL?
+
+ __ cmpptr(new_val, (int32_t) NULL_WORD);
+ __ jcc(Assembler::equal, done);
+
+ // storing region crossing non-NULL, is card already dirty?
+
+ const Register card_addr = tmp;
+ const Register cardtable = tmp2;
+
+ __ movptr(card_addr, store_addr);
+ __ shrptr(card_addr, CardTable::card_shift);
+ // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT
+ // a valid address and therefore is not properly handled by the relocation code.
+ __ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base());
+ __ addptr(card_addr, cardtable);
+
+ __ cmpb(Address(card_addr, 0), (int)G1CardTable::g1_young_card_val());
+ __ jcc(Assembler::equal, done);
+
+ __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
+ __ cmpb(Address(card_addr, 0), (int)G1CardTable::dirty_card_val());
+ __ jcc(Assembler::equal, done);
+
+
+ // storing a region crossing, non-NULL oop, card is clean.
+ // dirty card and log.
+
+ __ movb(Address(card_addr, 0), (int)G1CardTable::dirty_card_val());
+
+ __ cmpl(queue_index, 0);
+ __ jcc(Assembler::equal, runtime);
+ __ subl(queue_index, wordSize);
+ __ movptr(tmp2, buffer);
+#ifdef _LP64
+ __ movslq(rscratch1, queue_index);
+ __ addq(tmp2, rscratch1);
+ __ movq(Address(tmp2, 0), card_addr);
+#else
+ __ addl(tmp2, queue_index);
+ __ movl(Address(tmp2, 0), card_addr);
+#endif
+ __ jmp(done);
+
+ __ bind(runtime);
+ // save the live input values
+ __ push(store_addr);
+ __ push(new_val);
+#ifdef _LP64
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, r15_thread);
+#else
+ __ push(thread);
+ __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
+ __ pop(thread);
+#endif
+ __ pop(new_val);
+ __ pop(store_addr);
+
+ __ bind(done);
+}
+
+void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2) {
+ bool in_heap = (decorators & IN_HEAP) != 0;
+ bool in_concurrent_root = (decorators & IN_CONCURRENT_ROOT) != 0;
+
+ bool needs_pre_barrier = in_heap || in_concurrent_root;
+ bool needs_post_barrier = val != noreg && in_heap;
+
+ Register tmp3 = LP64_ONLY(r8) NOT_LP64(rsi);
+ Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx);
+ // flatten object address if needed
+ // We do it regardless of precise because we need the registers
+ if (dst.index() == noreg && dst.disp() == 0) {
+ if (dst.base() != tmp1) {
+ __ movptr(tmp1, dst.base());
+ }
+ } else {
+ __ lea(tmp1, dst);
+ }
+
+#ifndef _LP64
+ InterpreterMacroAssembler *imasm = static_cast<InterpreterMacroAssembler*>(masm);
+#endif
+
+ NOT_LP64(__ get_thread(rcx));
+ NOT_LP64(imasm->save_bcp());
+
+ if (needs_pre_barrier) {
+ g1_write_barrier_pre(masm /*masm*/,
+ tmp1 /* obj */,
+ tmp2 /* pre_val */,
+ rthread /* thread */,
+ tmp3 /* tmp */,
+ val != noreg /* tosca_live */,
+ false /* expand_call */);
+ }
+ if (val == noreg) {
+ BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg);
+ } else {
+ Register new_val = val;
+ if (needs_post_barrier) {
+ // G1 barrier needs uncompressed oop for region cross check.
+ if (UseCompressedOops) {
+ new_val = tmp2;
+ __ movptr(new_val, val);
+ }
+ }
+ BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg);
+ if (needs_post_barrier) {
+ g1_write_barrier_post(masm /*masm*/,
+ tmp1 /* store_adr */,
+ new_val /* new_val */,
+ rthread /* thread */,
+ tmp3 /* tmp */,
+ tmp2 /* tmp2 */);
+ }
+ }
+ NOT_LP64(imasm->restore_bcp());
+}
--- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,10 +30,30 @@
class G1BarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
- virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count);
- virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register addr, Register count, Register tmp);
+ virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count);
+ virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp);
+
+ void g1_write_barrier_pre(MacroAssembler* masm,
+ Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp,
+ bool tosca_live,
+ bool expand_call);
+
+ void g1_write_barrier_post(MacroAssembler* masm,
+ Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp,
+ Register tmp2);
+
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2);
+
+ public:
+ virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register dst, Address src, Register tmp1, Register tmp_thread);
};
#endif // CPU_X86_GC_G1_G1BARRIERSETASSEMBLER_X86_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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/shared/barrierSetAssembler.hpp"
+#include "interpreter/interp_masm.hpp"
+
+#define __ masm->
+
+void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register dst, Address src, Register tmp1, Register tmp_thread) {
+ bool on_heap = (decorators & IN_HEAP) != 0;
+ bool on_root = (decorators & IN_ROOT) != 0;
+ bool oop_not_null = (decorators & OOP_NOT_NULL) != 0;
+
+ switch (type) {
+ case T_OBJECT:
+ case T_ARRAY: {
+ if (on_heap) {
+#ifdef _LP64
+ if (UseCompressedOops) {
+ __ movl(dst, src);
+ if (oop_not_null) {
+ __ decode_heap_oop_not_null(dst);
+ } else {
+ __ decode_heap_oop(dst);
+ }
+ } else
+#endif
+ {
+ __ movptr(dst, src);
+ }
+ } else {
+ assert(on_root, "why else?");
+ __ movptr(dst, src);
+ }
+ break;
+ }
+ default: Unimplemented();
+ }
+}
+
+void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2) {
+ bool on_heap = (decorators & IN_HEAP) != 0;
+ bool on_root = (decorators & IN_ROOT) != 0;
+ bool oop_not_null = (decorators & OOP_NOT_NULL) != 0;
+
+ switch (type) {
+ case T_OBJECT:
+ case T_ARRAY: {
+ if (on_heap) {
+ if (val == noreg) {
+ assert(!oop_not_null, "inconsistent access");
+#ifdef _LP64
+ if (UseCompressedOops) {
+ __ movl(dst, (int32_t)NULL_WORD);
+ } else {
+ __ movslq(dst, (int32_t)NULL_WORD);
+ }
+#else
+ __ movl(dst, (int32_t)NULL_WORD);
+#endif
+ } else {
+#ifdef _LP64
+ if (UseCompressedOops) {
+ assert(!dst.uses(val), "not enough registers");
+ if (oop_not_null) {
+ __ encode_heap_oop_not_null(val);
+ } else {
+ __ encode_heap_oop(val);
+ }
+ __ movl(dst, val);
+ } else
+#endif
+ {
+ __ movptr(dst, val);
+ }
+ }
+ } else {
+ assert(on_root, "why else?");
+ assert(val != noreg, "not supported");
+ __ movptr(dst, val);
+ }
+ break;
+ }
+ default: Unimplemented();
+ }
+}
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -22,8 +22,8 @@
*
*/
-#ifndef CPU_X86_GC_G1_BARRIERSETASSEMBLER_X86_HPP
-#define CPU_X86_GC_G1_BARRIERSETASSEMBLER_X86_HPP
+#ifndef CPU_X86_GC_SHARED_BARRIERSETASSEMBLER_X86_HPP
+#define CPU_X86_GC_SHARED_BARRIERSETASSEMBLER_X86_HPP
#include "asm/macroAssembler.hpp"
#include "memory/allocation.hpp"
@@ -38,6 +38,13 @@
Register src, Register dst, Register count) {}
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register src, Register dst, Register count) {}
+
+ virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Register dst, Address src, Register tmp1, Register tmp_thread);
+ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2);
+
+ virtual void barrier_stubs_init() {}
};
-#endif // CPU_X86_GC_G1_BARRIERSETASSEMBLER_X86_HPP
+#endif // CPU_X86_GC_SHARED_BARRIERSETASSEMBLER_X86_HPP
--- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,7 +28,6 @@
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/cardTableBarrierSetAssembler.hpp"
-#include "gc/shared/collectedHeap.hpp"
#define __ masm->
@@ -44,7 +43,7 @@
void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, Register tmp) {
- BarrierSet *bs = Universe::heap()->barrier_set();
+ BarrierSet *bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
@@ -85,3 +84,70 @@
__ BIND(L_done);
}
+
+void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Address dst) {
+ // Does a store check for the oop in register obj. The content of
+ // register obj is destroyed afterwards.
+ BarrierSet* bs = BarrierSet::barrier_set();
+
+ CardTableBarrierSet* ct = barrier_set_cast<CardTableBarrierSet>(bs);
+ assert(sizeof(*ct->card_table()->byte_map_base()) == sizeof(jbyte), "adjust this code");
+
+ __ shrptr(obj, CardTable::card_shift);
+
+ Address card_addr;
+
+ // The calculation for byte_map_base is as follows:
+ // byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
+ // So this essentially converts an address to a displacement and it will
+ // never need to be relocated. On 64bit however the value may be too
+ // large for a 32bit displacement.
+ intptr_t disp = (intptr_t) ct->card_table()->byte_map_base();
+ if (__ is_simm32(disp)) {
+ card_addr = Address(noreg, obj, Address::times_1, disp);
+ } else {
+ // By doing it as an ExternalAddress 'disp' could be converted to a rip-relative
+ // displacement and done in a single instruction given favorable mapping and a
+ // smarter version of as_Address. However, 'ExternalAddress' generates a relocation
+ // entry and that entry is not properly handled by the relocation code.
+ AddressLiteral cardtable((address)ct->card_table()->byte_map_base(), relocInfo::none);
+ Address index(noreg, obj, Address::times_1);
+ card_addr = __ as_Address(ArrayAddress(cardtable, index));
+ }
+
+ int dirty = CardTable::dirty_card_val();
+ if (UseCondCardMark) {
+ Label L_already_dirty;
+ if (UseConcMarkSweepGC) {
+ __ membar(Assembler::StoreLoad);
+ }
+ __ cmpb(card_addr, dirty);
+ __ jcc(Assembler::equal, L_already_dirty);
+ __ movb(card_addr, dirty);
+ __ bind(L_already_dirty);
+ } else {
+ __ movb(card_addr, dirty);
+ }
+}
+
+void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2) {
+ bool in_heap = (decorators & IN_HEAP) != 0;
+
+ bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
+ bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
+ bool precise = on_array || on_anonymous;
+
+ bool needs_post_barrier = val != noreg && in_heap;
+
+ BarrierSetAssembler::store_at(masm, decorators, type, dst, val, noreg, noreg);
+ if (needs_post_barrier) {
+ // flatten object address if needed
+ if (!precise || (dst.index() == noreg && dst.disp() == 0)) {
+ store_check(masm, dst.base(), dst);
+ } else {
+ __ lea(tmp1, dst);
+ store_check(masm, tmp1, dst);
+ }
+ }
+}
--- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,8 +30,12 @@
class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler {
protected:
- virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr,
- Register count, Register tmp);
+ void store_check(MacroAssembler* masm, Register obj, Address dst);
+
+ virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp);
+
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2);
};
#endif // CPU_X86_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_X86_HPP
--- a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -78,3 +78,12 @@
gen_write_ref_array_post_barrier(masm, decorators, dst, count, tmp);
}
}
+
+void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2) {
+ if (type == T_OBJECT || type == T_ARRAY) {
+ oop_store_at(masm, decorators, type, dst, val, tmp1, tmp2);
+ } else {
+ BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2);
+ }
+}
--- a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,16 +28,26 @@
#include "asm/macroAssembler.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
+// The ModRefBarrierSetAssembler filters away accesses on BasicTypes other
+// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected
+// accesses, which are overridden in the concrete BarrierSetAssembler.
+
class ModRefBarrierSetAssembler: public BarrierSetAssembler {
protected:
- virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count) {}
- virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) {}
-
+ virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
+ Register addr, Register count) {}
+ virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
+ Register addr, Register count, Register tmp) {}
+ virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2) = 0;
public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register src, Register dst, Register count);
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register src, Register dst, Register count);
+
+ virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+ Address dst, Register val, Register tmp1, Register tmp2);
};
#endif // CPU_X86_GC_SHARED_MODREFBARRIERSETASSEMBLER_X86_HPP
--- a/src/hotspot/cpu/x86/interp_masm_x86.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -516,9 +516,7 @@
resolve_oop_handle(result);
// Add in the index
addptr(result, tmp);
- load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
- // The resulting oop is null if the reference is not yet resolved.
- // It is Universe::the_null_sentinel() if the reference resolved to NULL via condy.
+ load_heap_oop(result, Address(result, arrayOopDesc::base_offset_in_bytes(T_OBJECT)), tmp);
}
// load cpool->resolved_klass_at(index)
--- a/src/hotspot/cpu/x86/interp_masm_x86.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,12 +35,13 @@
typedef ByteSize (*OffsetFunction)(uint);
class InterpreterMacroAssembler: public MacroAssembler {
-
- protected:
+ public:
// Interpreter specific version of call_VM_base
virtual void call_VM_leaf_base(address entry_point,
int number_of_arguments);
+ protected:
+
virtual void call_VM_base(Register oop_result,
Register java_thread,
Register last_java_sp,
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -27,12 +27,13 @@
#include "asm/assembler.hpp"
#include "asm/assembler.inline.hpp"
#include "compiler/disassembler.hpp"
-#include "gc/shared/cardTable.hpp"
-#include "gc/shared/cardTableBarrierSet.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
+#include "oops/access.hpp"
#include "oops/klass.inline.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/biasedLocking.hpp"
@@ -45,12 +46,6 @@
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
#include "crc32c.h"
#ifdef COMPILER2
#include "opto/intrinsicnode.hpp"
@@ -5240,6 +5235,12 @@
}
}
+void MacroAssembler::clear_jweak_tag(Register possibly_jweak) {
+ const int32_t inverted_jweak_mask = ~static_cast<int32_t>(JNIHandles::weak_tag_mask);
+ STATIC_ASSERT(inverted_jweak_mask == -2); // otherwise check this code
+ // The inverted mask is sign-extended
+ andptr(possibly_jweak, inverted_jweak_mask);
+}
void MacroAssembler::resolve_jobject(Register value,
Register thread,
@@ -5251,296 +5252,18 @@
testptr(value, JNIHandles::weak_tag_mask); // Test for jweak tag.
jcc(Assembler::zero, not_weak);
// Resolve jweak.
- movptr(value, Address(value, -JNIHandles::weak_tag_value));
+ access_load_at(T_OBJECT, IN_ROOT | ON_PHANTOM_OOP_REF,
+ value, Address(value, -JNIHandles::weak_tag_value), tmp, thread);
verify_oop(value);
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- g1_write_barrier_pre(noreg /* obj */,
- value /* pre_val */,
- thread /* thread */,
- tmp /* tmp */,
- true /* tosca_live */,
- true /* expand_call */);
- }
-#endif // INCLUDE_ALL_GCS
jmp(done);
bind(not_weak);
// Resolve (untagged) jobject.
- movptr(value, Address(value, 0));
+ access_load_at(T_OBJECT, IN_ROOT | IN_CONCURRENT_ROOT,
+ value, Address(value, 0), tmp, thread);
verify_oop(value);
bind(done);
}
-void MacroAssembler::clear_jweak_tag(Register possibly_jweak) {
- const int32_t inverted_jweak_mask = ~static_cast<int32_t>(JNIHandles::weak_tag_mask);
- STATIC_ASSERT(inverted_jweak_mask == -2); // otherwise check this code
- // The inverted mask is sign-extended
- andptr(possibly_jweak, inverted_jweak_mask);
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-#if INCLUDE_ALL_GCS
-
-void MacroAssembler::g1_write_barrier_pre(Register obj,
- Register pre_val,
- Register thread,
- Register tmp,
- bool tosca_live,
- bool expand_call) {
-
- // If expand_call is true then we expand the call_VM_leaf macro
- // directly to skip generating the check by
- // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
-
-#ifdef _LP64
- assert(thread == r15_thread, "must be");
-#endif // _LP64
-
- Label done;
- Label runtime;
-
- assert(pre_val != noreg, "check this code");
-
- if (obj != noreg) {
- assert_different_registers(obj, pre_val, tmp);
- assert(pre_val != rax, "check this code");
- }
-
- Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active()));
- Address index(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_index()));
- Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf()));
-
-
- // Is marking active?
- if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) {
- cmpl(in_progress, 0);
- } else {
- assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption");
- cmpb(in_progress, 0);
- }
- jcc(Assembler::equal, done);
-
- // Do we need to load the previous value?
- if (obj != noreg) {
- load_heap_oop(pre_val, Address(obj, 0));
- }
-
- // Is the previous value null?
- cmpptr(pre_val, (int32_t) NULL_WORD);
- jcc(Assembler::equal, done);
-
- // Can we store original value in the thread's buffer?
- // Is index == 0?
- // (The index field is typed as size_t.)
-
- movptr(tmp, index); // tmp := *index_adr
- cmpptr(tmp, 0); // tmp == 0?
- jcc(Assembler::equal, runtime); // If yes, goto runtime
-
- subptr(tmp, wordSize); // tmp := tmp - wordSize
- movptr(index, tmp); // *index_adr := tmp
- addptr(tmp, buffer); // tmp := tmp + *buffer_adr
-
- // Record the previous value
- movptr(Address(tmp, 0), pre_val);
- jmp(done);
-
- bind(runtime);
- // save the live input values
- if(tosca_live) push(rax);
-
- if (obj != noreg && obj != rax)
- push(obj);
-
- if (pre_val != rax)
- push(pre_val);
-
- // Calling the runtime using the regular call_VM_leaf mechanism generates
- // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
- // that checks that the *(ebp+frame::interpreter_frame_last_sp) == NULL.
- //
- // If we care generating the pre-barrier without a frame (e.g. in the
- // intrinsified Reference.get() routine) then ebp might be pointing to
- // the caller frame and so this check will most likely fail at runtime.
- //
- // Expanding the call directly bypasses the generation of the check.
- // So when we do not have have a full interpreter frame on the stack
- // expand_call should be passed true.
-
- NOT_LP64( push(thread); )
-
- if (expand_call) {
- LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); )
- pass_arg1(this, thread);
- pass_arg0(this, pre_val);
- MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), 2);
- } else {
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
- }
-
- NOT_LP64( pop(thread); )
-
- // save the live input values
- if (pre_val != rax)
- pop(pre_val);
-
- if (obj != noreg && obj != rax)
- pop(obj);
-
- if(tosca_live) pop(rax);
-
- bind(done);
-}
-
-void MacroAssembler::g1_write_barrier_post(Register store_addr,
- Register new_val,
- Register thread,
- Register tmp,
- Register tmp2) {
-#ifdef _LP64
- assert(thread == r15_thread, "must be");
-#endif // _LP64
-
- Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_index()));
- Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf()));
-
- CardTableBarrierSet* ctbs =
- barrier_set_cast<CardTableBarrierSet>(Universe::heap()->barrier_set());
- CardTable* ct = ctbs->card_table();
- assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
-
- Label done;
- Label runtime;
-
- // Does store cross heap regions?
-
- movptr(tmp, store_addr);
- xorptr(tmp, new_val);
- shrptr(tmp, HeapRegion::LogOfHRGrainBytes);
- jcc(Assembler::equal, done);
-
- // crosses regions, storing NULL?
-
- cmpptr(new_val, (int32_t) NULL_WORD);
- jcc(Assembler::equal, done);
-
- // storing region crossing non-NULL, is card already dirty?
-
- const Register card_addr = tmp;
- const Register cardtable = tmp2;
-
- movptr(card_addr, store_addr);
- shrptr(card_addr, CardTable::card_shift);
- // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT
- // a valid address and therefore is not properly handled by the relocation code.
- movptr(cardtable, (intptr_t)ct->byte_map_base());
- addptr(card_addr, cardtable);
-
- cmpb(Address(card_addr, 0), (int)G1CardTable::g1_young_card_val());
- jcc(Assembler::equal, done);
-
- membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
- cmpb(Address(card_addr, 0), (int)CardTable::dirty_card_val());
- jcc(Assembler::equal, done);
-
-
- // storing a region crossing, non-NULL oop, card is clean.
- // dirty card and log.
-
- movb(Address(card_addr, 0), (int)CardTable::dirty_card_val());
-
- cmpl(queue_index, 0);
- jcc(Assembler::equal, runtime);
- subl(queue_index, wordSize);
- movptr(tmp2, buffer);
-#ifdef _LP64
- movslq(rscratch1, queue_index);
- addq(tmp2, rscratch1);
- movq(Address(tmp2, 0), card_addr);
-#else
- addl(tmp2, queue_index);
- movl(Address(tmp2, 0), card_addr);
-#endif
- jmp(done);
-
- bind(runtime);
- // save the live input values
- push(store_addr);
- push(new_val);
-#ifdef _LP64
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, r15_thread);
-#else
- push(thread);
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
- pop(thread);
-#endif
- pop(new_val);
- pop(store_addr);
-
- bind(done);
-}
-
-#endif // INCLUDE_ALL_GCS
-//////////////////////////////////////////////////////////////////////////////////
-
-
-void MacroAssembler::store_check(Register obj, Address dst) {
- store_check(obj);
-}
-
-void MacroAssembler::store_check(Register obj) {
- // Does a store check for the oop in register obj. The content of
- // register obj is destroyed afterwards.
- BarrierSet* bs = Universe::heap()->barrier_set();
- assert(bs->kind() == BarrierSet::CardTableBarrierSet,
- "Wrong barrier set kind");
-
- CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
- CardTable* ct = ctbs->card_table();
- assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
-
- shrptr(obj, CardTable::card_shift);
-
- Address card_addr;
-
- // The calculation for byte_map_base is as follows:
- // byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
- // So this essentially converts an address to a displacement and it will
- // never need to be relocated. On 64bit however the value may be too
- // large for a 32bit displacement.
- intptr_t disp = (intptr_t) ct->byte_map_base();
- if (is_simm32(disp)) {
- card_addr = Address(noreg, obj, Address::times_1, disp);
- } else {
- // By doing it as an ExternalAddress 'disp' could be converted to a rip-relative
- // displacement and done in a single instruction given favorable mapping and a
- // smarter version of as_Address. However, 'ExternalAddress' generates a relocation
- // entry and that entry is not properly handled by the relocation code.
- AddressLiteral cardtable((address)ct->byte_map_base(), relocInfo::none);
- Address index(noreg, obj, Address::times_1);
- card_addr = as_Address(ArrayAddress(cardtable, index));
- }
-
- int dirty = CardTable::dirty_card_val();
- if (UseCondCardMark) {
- Label L_already_dirty;
- if (UseConcMarkSweepGC) {
- membar(Assembler::StoreLoad);
- }
- cmpb(card_addr, dirty);
- jcc(Assembler::equal, L_already_dirty);
- movb(card_addr, dirty);
- bind(L_already_dirty);
- } else {
- movb(card_addr, dirty);
- }
-}
-
void MacroAssembler::subptr(Register dst, int32_t imm32) {
LP64_ONLY(subq(dst, imm32)) NOT_LP64(subl(dst, imm32));
}
@@ -6591,69 +6314,47 @@
movptr(Address(dst, oopDesc::klass_offset_in_bytes()), src);
}
-void MacroAssembler::load_heap_oop(Register dst, Address src) {
-#ifdef _LP64
- // FIXME: Must change all places where we try to load the klass.
- if (UseCompressedOops) {
- movl(dst, src);
- decode_heap_oop(dst);
- } else
-#endif
- movptr(dst, src);
+void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators, Register dst, Address src,
+ Register tmp1, Register thread_tmp) {
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bool as_raw = (decorators & AS_RAW) != 0;
+ if (as_raw) {
+ bs->BarrierSetAssembler::load_at(this, decorators, type, dst, src, tmp1, thread_tmp);
+ } else {
+ bs->load_at(this, decorators, type, dst, src, tmp1, thread_tmp);
+ }
+}
+
+void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register src,
+ Register tmp1, Register tmp2) {
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+ bool as_raw = (decorators & AS_RAW) != 0;
+ if (as_raw) {
+ bs->BarrierSetAssembler::store_at(this, decorators, type, dst, src, tmp1, tmp2);
+ } else {
+ bs->store_at(this, decorators, type, dst, src, tmp1, tmp2);
+ }
+}
+
+void MacroAssembler::load_heap_oop(Register dst, Address src, Register tmp1,
+ Register thread_tmp, DecoratorSet decorators) {
+ access_load_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, thread_tmp);
}
// Doesn't do verfication, generates fixed size code
-void MacroAssembler::load_heap_oop_not_null(Register dst, Address src) {
-#ifdef _LP64
- if (UseCompressedOops) {
- movl(dst, src);
- decode_heap_oop_not_null(dst);
- } else
-#endif
- movptr(dst, src);
-}
-
-void MacroAssembler::store_heap_oop(Address dst, Register src) {
-#ifdef _LP64
- if (UseCompressedOops) {
- assert(!dst.uses(src), "not enough registers");
- encode_heap_oop(src);
- movl(dst, src);
- } else
-#endif
- movptr(dst, src);
-}
-
-void MacroAssembler::cmp_heap_oop(Register src1, Address src2, Register tmp) {
- assert_different_registers(src1, tmp);
-#ifdef _LP64
- if (UseCompressedOops) {
- bool did_push = false;
- if (tmp == noreg) {
- tmp = rax;
- push(tmp);
- did_push = true;
- assert(!src2.uses(rsp), "can't push");
- }
- load_heap_oop(tmp, src2);
- cmpptr(src1, tmp);
- if (did_push) pop(tmp);
- } else
-#endif
- cmpptr(src1, src2);
+void MacroAssembler::load_heap_oop_not_null(Register dst, Address src, Register tmp1,
+ Register thread_tmp, DecoratorSet decorators) {
+ access_load_at(T_OBJECT, IN_HEAP | OOP_NOT_NULL | decorators, dst, src, tmp1, thread_tmp);
+}
+
+void MacroAssembler::store_heap_oop(Address dst, Register src, Register tmp1,
+ Register tmp2, DecoratorSet decorators) {
+ access_store_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, tmp2);
}
// Used for storing NULLs.
void MacroAssembler::store_heap_oop_null(Address dst) {
-#ifdef _LP64
- if (UseCompressedOops) {
- movl(dst, (int32_t)NULL_WORD);
- } else {
- movslq(dst, (int32_t)NULL_WORD);
- }
-#else
- movl(dst, (int32_t)NULL_WORD);
-#endif
+ access_store_at(T_OBJECT, IN_HEAP, dst, noreg, noreg, noreg);
}
#ifdef _LP64
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -38,11 +38,7 @@
friend class LIR_Assembler;
friend class Runtime1; // as_Address()
- protected:
-
- Address as_Address(AddressLiteral adr);
- Address as_Address(ArrayAddress adr);
-
+ public:
// Support for VM calls
//
// This is the base routine called by the different versions of call_VM_leaf. The interpreter
@@ -54,6 +50,7 @@
int number_of_arguments // the number of arguments to pop after the call
);
+ protected:
// This is the base routine called by the different versions of call_VM. The interpreter
// may customize this version by overriding it for its purposes (e.g., to save/restore
// additional registers when doing a VM call).
@@ -87,6 +84,9 @@
virtual void check_and_handle_popframe(Register java_thread);
virtual void check_and_handle_earlyret(Register java_thread);
+ Address as_Address(AddressLiteral adr);
+ Address as_Address(ArrayAddress adr);
+
// Support for NULL-checks
//
// Generates code that causes a NULL OS exception if the content of reg is NULL.
@@ -293,29 +293,9 @@
// thread in the default location (r15_thread on 64bit)
void reset_last_Java_frame(bool clear_fp);
- // Stores
- void store_check(Register obj); // store check for obj - register is destroyed afterwards
- void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed)
-
- void resolve_jobject(Register value, Register thread, Register tmp);
+ // jobjects
void clear_jweak_tag(Register possibly_jweak);
-
-#if INCLUDE_ALL_GCS
-
- void g1_write_barrier_pre(Register obj,
- Register pre_val,
- Register thread,
- Register tmp,
- bool tosca_live,
- bool expand_call);
-
- void g1_write_barrier_post(Register store_addr,
- Register new_val,
- Register thread,
- Register tmp,
- Register tmp2);
-
-#endif // INCLUDE_ALL_GCS
+ void resolve_jobject(Register value, Register thread, Register tmp);
// C 'boolean' to Java boolean: x == 0 ? 0 : 1
void c2bool(Register x);
@@ -334,10 +314,17 @@
void load_klass(Register dst, Register src);
void store_klass(Register dst, Register src);
- void load_heap_oop(Register dst, Address src);
- void load_heap_oop_not_null(Register dst, Address src);
- void store_heap_oop(Address dst, Register src);
- void cmp_heap_oop(Register src1, Address src2, Register tmp = noreg);
+ void access_load_at(BasicType type, DecoratorSet decorators, Register dst, Address src,
+ Register tmp1, Register thread_tmp);
+ void access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register src,
+ Register tmp1, Register tmp2);
+
+ void load_heap_oop(Register dst, Address src, Register tmp1 = noreg,
+ Register thread_tmp = noreg, DecoratorSet decorators = 0);
+ void load_heap_oop_not_null(Register dst, Address src, Register tmp1 = noreg,
+ Register thread_tmp = noreg, DecoratorSet decorators = 0);
+ void store_heap_oop(Address dst, Register src, Register tmp1 = noreg,
+ Register tmp2 = noreg, DecoratorSet decorators = 0);
// Used for storing NULL. All other oop constants should be
// stored using routines that take a jobject.
--- a/src/hotspot/cpu/x86/methodHandles_x86.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/methodHandles_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -168,11 +168,11 @@
// Load the invoker, as MH -> MH.form -> LF.vmentry
__ verify_oop(recv);
- __ load_heap_oop(method_temp, Address(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes())));
+ __ load_heap_oop(method_temp, Address(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset_in_bytes())), temp2);
__ verify_oop(method_temp);
- __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes())));
+ __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset_in_bytes())), temp2);
__ verify_oop(method_temp);
- __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes())));
+ __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset_in_bytes())), temp2);
__ verify_oop(method_temp);
__ movptr(method_temp, Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset_in_bytes())));
@@ -361,7 +361,7 @@
if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) {
Label L_ok;
Register temp2_defc = temp2;
- __ load_heap_oop(temp2_defc, member_clazz);
+ __ load_heap_oop(temp2_defc, member_clazz, temp3);
load_klass_from_Class(_masm, temp2_defc);
__ verify_klass_ptr(temp2_defc);
__ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, L_ok);
@@ -437,6 +437,8 @@
verify_ref_kind(_masm, JVM_REF_invokeInterface, member_reg, temp3);
}
+ BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+
Register temp3_intf = temp3;
__ load_heap_oop(temp3_intf, member_clazz);
load_klass_from_Class(_masm, temp3_intf);
--- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -845,7 +845,7 @@
decorators |= ARRAYCOPY_ALIGNED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, t, from, to, count);
__ subptr(to, from); // to --> to_from
@@ -1034,7 +1034,7 @@
decorators |= ARRAYCOPY_ALIGNED;
}
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, t, from, to, count);
// copy from high to low
@@ -1389,7 +1389,7 @@
}
BasicType type = T_OBJECT;
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, type, from, to, count);
// Copy from low to high addresses, indexed from the end of each array.
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1829,7 +1829,7 @@
}
BasicType type = is_oop ? T_OBJECT : T_INT;
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, type, from, to, count);
// 'from', 'to' and 'count' are now valid
@@ -1923,7 +1923,7 @@
}
BasicType type = is_oop ? T_OBJECT : T_INT;
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
// no registers are destroyed by this call
bs->arraycopy_prologue(_masm, decorators, type, from, to, count);
@@ -2027,7 +2027,7 @@
}
BasicType type = is_oop ? T_OBJECT : T_LONG;
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, type, from, to, qword_count);
// Copy from low to high addresses. Use 'to' as scratch.
@@ -2120,7 +2120,7 @@
}
BasicType type = is_oop ? T_OBJECT : T_LONG;
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, type, from, to, qword_count);
__ jmp(L_copy_bytes);
@@ -2300,7 +2300,7 @@
}
BasicType type = T_OBJECT;
- BarrierSetAssembler *bs = Universe::heap()->barrier_set()->barrier_set_assembler();
+ BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->arraycopy_prologue(_masm, decorators, type, from, to, count);
// Copy from low to high addresses, indexed from the end of each array.
@@ -2323,13 +2323,13 @@
__ align(OptoLoopAlignment);
__ BIND(L_store_element);
- __ store_heap_oop(to_element_addr, rax_oop); // store the oop
+ __ store_heap_oop(to_element_addr, rax_oop, noreg, noreg, AS_RAW); // store the oop
__ increment(count); // increment the count toward zero
__ jcc(Assembler::zero, L_do_card_marks);
// ======== loop entry is here ========
__ BIND(L_load_element);
- __ load_heap_oop(rax_oop, from_element_addr); // load the oop
+ __ load_heap_oop(rax_oop, from_element_addr, noreg, noreg, AS_RAW); // load the oop
__ testptr(rax_oop, rax_oop);
__ jcc(Assembler::zero, L_store_element);
--- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interp_masm.hpp"
#include "interpreter/interpreter.hpp"
@@ -696,29 +697,18 @@
// Method entry for java.lang.ref.Reference.get.
address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
-#if INCLUDE_ALL_GCS
// Code: _aload_0, _getfield, _areturn
// parameter size = 1
//
// The code that gets generated by this routine is split into 2 parts:
- // 1. The "intrinsified" code for G1 (or any SATB based GC),
+ // 1. The "intrinsified" code performing an ON_WEAK_OOP_REF load,
// 2. The slow path - which is an expansion of the regular method entry.
//
// Notes:-
- // * In the G1 code we do not check whether we need to block for
- // a safepoint. If G1 is enabled then we must execute the specialized
- // code for Reference.get (except when the Reference object is null)
- // so that we can log the value in the referent field with an SATB
- // update buffer.
- // If the code for the getfield template is modified so that the
- // G1 pre-barrier code is executed when the current method is
- // Reference.get() then going through the normal method entry
- // will be fine.
- // * The G1 code can, however, check the receiver object (the instance
- // of java.lang.Reference) and jump to the slow path if null. If the
- // Reference object is null then we obviously cannot fetch the referent
- // and so we don't need to call the G1 pre-barrier. Thus we can use the
- // regular method entry code to generate the NPE.
+ // * An intrinsic is always executed, where an ON_WEAK_OOP_REF load is performed.
+ // * We may jump to the slow path iff the receiver is null. If the
+ // Reference object is null then we no longer perform an ON_WEAK_OOP_REF load
+ // Thus we can use the regular method entry code to generate the NPE.
//
// rbx: Method*
@@ -729,63 +719,41 @@
const int referent_offset = java_lang_ref_Reference::referent_offset;
guarantee(referent_offset > 0, "referent offset not initialized");
- if (UseG1GC) {
- Label slow_path;
- // rbx: method
+ Label slow_path;
+ // rbx: method
- // Check if local 0 != NULL
- // If the receiver is null then it is OK to jump to the slow path.
- __ movptr(rax, Address(rsp, wordSize));
-
- __ testptr(rax, rax);
- __ jcc(Assembler::zero, slow_path);
+ // Check if local 0 != NULL
+ // If the receiver is null then it is OK to jump to the slow path.
+ __ movptr(rax, Address(rsp, wordSize));
- // rax: local 0
- // rbx: method (but can be used as scratch now)
- // rdx: scratch
- // rdi: scratch
+ __ testptr(rax, rax);
+ __ jcc(Assembler::zero, slow_path);
- // Preserve the sender sp in case the pre-barrier
- // calls the runtime
- NOT_LP64(__ push(rsi));
-
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer.
-
- // Load the value of the referent field.
- const Address field_address(rax, referent_offset);
- __ load_heap_oop(rax, field_address);
+ // rax: local 0
+ // rbx: method (but can be used as scratch now)
+ // rdx: scratch
+ // rdi: scratch
- const Register sender_sp = NOT_LP64(rsi) LP64_ONLY(r13);
- const Register thread = NOT_LP64(rcx) LP64_ONLY(r15_thread);
- NOT_LP64(__ get_thread(thread));
+ // Preserve the sender sp in case the load barrier
+ // calls the runtime
+ NOT_LP64(__ push(rsi));
- // Generate the G1 pre-barrier code to log the value of
- // the referent field in an SATB buffer.
- __ g1_write_barrier_pre(noreg /* obj */,
- rax /* pre_val */,
- thread /* thread */,
- rbx /* tmp */,
- true /* tosca_live */,
- true /* expand_call */);
+ // Load the value of the referent field.
+ const Address field_address(rax, referent_offset);
+ __ load_heap_oop(rax, field_address, /*tmp1*/ rbx, /*tmp_thread*/ rdx, ON_WEAK_OOP_REF);
- // _areturn
- NOT_LP64(__ pop(rsi)); // get sender sp
- __ pop(rdi); // get return address
- __ mov(rsp, sender_sp); // set sp to sender sp
- __ jmp(rdi);
- __ ret(0);
+ // _areturn
+ const Register sender_sp = NOT_LP64(rsi) LP64_ONLY(r13);
+ NOT_LP64(__ pop(rsi)); // get sender sp
+ __ pop(rdi); // get return address
+ __ mov(rsp, sender_sp); // set sp to sender sp
+ __ jmp(rdi);
+ __ ret(0);
- // generate a vanilla interpreter entry as the slow path
- __ bind(slow_path);
- __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
- return entry;
- }
-#endif // INCLUDE_ALL_GCS
-
- // If G1 is not enabled then attempt to go through the accessor entry point
- // Reference.get is an accessor
- return NULL;
+ // generate a vanilla interpreter entry as the slow path
+ __ bind(slow_path);
+ __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
+ return entry;
}
void TemplateInterpreterGenerator::bang_stack_shadow_pages(bool native_call) {
--- a/src/hotspot/cpu/x86/templateTable_x86.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/x86/templateTable_x86.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -149,84 +149,18 @@
static void do_oop_store(InterpreterMacroAssembler* _masm,
- Address obj,
+ Address dst,
Register val,
- BarrierSet::Name barrier,
- bool precise) {
+ DecoratorSet decorators = 0) {
assert(val == noreg || val == rax, "parameter is just for looks");
- switch (barrier) {
-#if INCLUDE_ALL_GCS
- case BarrierSet::G1BarrierSet:
- {
- // flatten object address if needed
- // We do it regardless of precise because we need the registers
- if (obj.index() == noreg && obj.disp() == 0) {
- if (obj.base() != rdx) {
- __ movptr(rdx, obj.base());
- }
- } else {
- __ lea(rdx, obj);
- }
-
- Register rtmp = LP64_ONLY(r8) NOT_LP64(rsi);
- Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx);
-
- NOT_LP64(__ get_thread(rcx));
- NOT_LP64(__ save_bcp());
-
- __ g1_write_barrier_pre(rdx /* obj */,
- rbx /* pre_val */,
- rthread /* thread */,
- rtmp /* tmp */,
- val != noreg /* tosca_live */,
- false /* expand_call */);
- if (val == noreg) {
- __ store_heap_oop_null(Address(rdx, 0));
- } else {
- // G1 barrier needs uncompressed oop for region cross check.
- Register new_val = val;
- if (UseCompressedOops) {
- new_val = rbx;
- __ movptr(new_val, val);
- }
- __ store_heap_oop(Address(rdx, 0), val);
- __ g1_write_barrier_post(rdx /* store_adr */,
- new_val /* new_val */,
- rthread /* thread */,
- rtmp /* tmp */,
- rbx /* tmp2 */);
- }
- NOT_LP64( __ restore_bcp());
- }
- break;
-#endif // INCLUDE_ALL_GCS
- case BarrierSet::CardTableBarrierSet:
- {
- if (val == noreg) {
- __ store_heap_oop_null(obj);
- } else {
- __ store_heap_oop(obj, val);
- // flatten object address if needed
- if (!precise || (obj.index() == noreg && obj.disp() == 0)) {
- __ store_check(obj.base());
- } else {
- __ lea(rdx, obj);
- __ store_check(rdx);
- }
- }
- }
- break;
- case BarrierSet::ModRef:
- if (val == noreg) {
- __ store_heap_oop_null(obj);
- } else {
- __ store_heap_oop(obj, val);
- }
- break;
- default :
- ShouldNotReachHere();
-
- }
+ __ store_heap_oop(dst, val, rdx, rbx, decorators);
+}
+
+static void do_oop_load(InterpreterMacroAssembler* _masm,
+ Address src,
+ Register dst,
+ DecoratorSet decorators = 0) {
+ __ load_heap_oop(dst, src, rdx, rbx, decorators);
}
Address TemplateTable::at_bcp(int offset) {
@@ -876,9 +810,12 @@
// rax: index
// rdx: array
index_check(rdx, rax); // kills rbx
- __ load_heap_oop(rax, Address(rdx, rax,
- UseCompressedOops ? Address::times_4 : Address::times_ptr,
- arrayOopDesc::base_offset_in_bytes(T_OBJECT)));
+ do_oop_load(_masm,
+ Address(rdx, rax,
+ UseCompressedOops ? Address::times_4 : Address::times_ptr,
+ arrayOopDesc::base_offset_in_bytes(T_OBJECT)),
+ rax,
+ IN_HEAP_ARRAY);
}
void TemplateTable::baload() {
@@ -1189,7 +1126,7 @@
// Get the value we will store
__ movptr(rax, at_tos());
// Now store using the appropriate barrier
- do_oop_store(_masm, Address(rdx, 0), rax, _bs->kind(), true);
+ do_oop_store(_masm, Address(rdx, 0), rax, IN_HEAP_ARRAY);
__ jmp(done);
// Have a NULL in rax, rdx=array, ecx=index. Store NULL at ary[idx]
@@ -1197,7 +1134,7 @@
__ profile_null_seen(rbx);
// Store a NULL
- do_oop_store(_masm, element_address, noreg, _bs->kind(), true);
+ do_oop_store(_masm, element_address, noreg, IN_HEAP_ARRAY);
// Pop stack arguments
__ bind(done);
@@ -2951,7 +2888,7 @@
__ cmpl(flags, atos);
__ jcc(Assembler::notEqual, notObj);
// atos
- __ load_heap_oop(rax, field);
+ do_oop_load(_masm, field, rax);
__ push(atos);
if (!is_static && rc == may_rewrite) {
patch_bytecode(Bytecodes::_fast_agetfield, bc, rbx);
@@ -3226,7 +3163,7 @@
__ pop(atos);
if (!is_static) pop_and_check_object(obj);
// Store into the field
- do_oop_store(_masm, field, rax, _bs->kind(), false);
+ do_oop_store(_masm, field, rax);
if (!is_static && rc == may_rewrite) {
patch_bytecode(Bytecodes::_fast_aputfield, bc, rbx, true, byte_no);
}
@@ -3479,7 +3416,7 @@
// access field
switch (bytecode()) {
case Bytecodes::_fast_aputfield:
- do_oop_store(_masm, field, rax, _bs->kind(), false);
+ do_oop_store(_masm, field, rax);
break;
case Bytecodes::_fast_lputfield:
#ifdef _LP64
@@ -3568,7 +3505,7 @@
// access field
switch (bytecode()) {
case Bytecodes::_fast_agetfield:
- __ load_heap_oop(rax, field);
+ do_oop_load(_masm, field, rax);
__ verify_oop(rax);
break;
case Bytecodes::_fast_lgetfield:
@@ -3630,7 +3567,7 @@
__ movl(rax, field);
break;
case atos:
- __ load_heap_oop(rax, field);
+ do_oop_load(_masm, field, rax);
__ verify_oop(rax);
break;
case ftos:
--- a/src/hotspot/cpu/zero/assembler_zero.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/zero/assembler_zero.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -39,7 +39,6 @@
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/heapRegion.hpp"
#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/cpu/zero/cppInterpreter_zero.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/zero/cppInterpreter_zero.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -275,7 +275,7 @@
markOop disp = lockee->mark()->set_unlocked();
monitor->lock()->set_displaced_header(disp);
- if (Atomic::cmpxchg((markOop)monitor, lockee->mark_addr(), disp) != disp) {
+ if (lockee->cas_set_mark((markOop)monitor, disp) != disp) {
if (thread->is_lock_owned((address) disp->clear_lock_bits())) {
monitor->lock()->set_displaced_header(NULL);
}
--- a/src/hotspot/cpu/zero/gc/shared/barrierSetAssembler_zero.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/cpu/zero/gc/shared/barrierSetAssembler_zero.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -22,9 +22,9 @@
*
*/
-#ifndef CPU_ZERO_GC_G1_BARRIERSETASSEMBLER_ZERO_HPP
-#define CPU_ZERO_GC_G1_BARRIERSETASSEMBLER_ZERO_HPP
+#ifndef CPU_ZERO_GC_SHARED_BARRIERSETASSEMBLER_ZERO_HPP
+#define CPU_ZERO_GC_SHARED_BARRIERSETASSEMBLER_ZERO_HPP
class BarrierSetAssembler;
-#endif // CPU_ZERO_GC_G1_BARRIERSETASSEMBLER_ZERO_HPP
+#endif // CPU_ZERO_GC_SHARED_BARRIERSETASSEMBLER_ZERO_HPP
--- a/src/hotspot/os/aix/attachListener_aix.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/os/aix/attachListener_aix.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2012, 2018 SAP SE. All rights reserved.
* 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,12 +30,12 @@
#include "services/attachListener.hpp"
#include "services/dtraceAttacher.hpp"
-#include <unistd.h>
#include <signal.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/stat.h>
+#include <unistd.h>
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path)
@@ -145,10 +145,10 @@
}
char* next() {
if (*_pos == '\0') {
+ // advance the iterator if possible (null arguments)
if (_pos < _end) {
_pos += 1;
}
-
return NULL;
}
char* res = _pos;
@@ -233,10 +233,10 @@
// put in listen mode, set permissions, and rename into place
res = ::listen(listener, 5);
if (res == 0) {
- RESTARTABLE(::chmod(initial_path, (S_IREAD|S_IWRITE) & ~(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)), res);
- if (res == 0) {
- res = ::rename(initial_path, path);
- }
+ RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res);
+ if (res == 0) {
+ res = ::rename(initial_path, path);
+ }
}
if (res == -1) {
::close(listener);
@@ -284,10 +284,12 @@
// Don't block on interrupts because this will
// hang in the clean-up when shutting down.
n = read(s, buf+off, left);
+ assert(n <= left, "buffer was too small, impossible!");
+ buf[max_len - 1] = '\0';
if (n == -1) {
return NULL; // reset by peer or other error
}
- if (n == 0) { // end of file reached
+ if (n == 0) {
break;
}
for (int i=0; i<n; i++) {
@@ -362,7 +364,7 @@
socklen_t len = sizeof(addr);
memset(&addr, 0, len);
// We must prevent accept blocking on the socket if it has been shut down.
- // Therefore we allow interrups and check whether we have been shut down already.
+ // Therefore we allow interrupts and check whether we have been shut down already.
if (AixAttachListener::is_shutdown()) {
return NULL;
}
@@ -371,19 +373,11 @@
return NULL; // log a warning?
}
- // Added timeouts for read and write. If we get no request within the
- // next AttachListenerTimeout milliseconds we just finish the connection.
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = AttachListenerTimeout * 1000;
- ::setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
- ::setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
-
// get the credentials of the peer and check the effective uid/guid
- // - check with jeff on this.
struct peercred_struct cred_info;
socklen_t optlen = sizeof(cred_info);
if (::getsockopt(s, SOL_SOCKET, SO_PEERID, (void*)&cred_info, &optlen) == -1) {
+ log_debug(attach)("Failed to get socket option SO_PEERID");
::close(s);
continue;
}
@@ -391,6 +385,7 @@
gid_t egid = getegid();
if (cred_info.euid != euid || cred_info.egid != egid) {
+ log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", cred_info.euid, cred_info.egid, euid, egid);
::close(s);
continue;
}
@@ -532,10 +527,10 @@
if (init_at_startup() || is_initialized()) {
return false; // initialized at startup or already initialized
}
- char fn[PATH_MAX+1];
- sprintf(fn, ".attach_pid%d", os::current_process_id());
+ char fn[PATH_MAX + 1];
int ret;
struct stat64 st;
+ sprintf(fn, ".attach_pid%d", os::current_process_id());
RESTARTABLE(::stat64(fn, &st), ret);
if (ret == -1) {
log_trace(attach)("Failed to find attach file: %s, trying alternate", fn);
@@ -551,7 +546,7 @@
// a bogus user creates the file
if (st.st_uid == geteuid()) {
init();
- log_trace(attach)("Attach trigerred by %s", fn);
+ log_trace(attach)("Attach triggered by %s", fn);
return true;
} else {
log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());
--- a/src/hotspot/os/aix/globals_aix.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/os/aix/globals_aix.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018 SAP SE. All rights reserved.
* 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,10 +51,6 @@
product(bool, AllowExtshm, false, \
"Allow VM to run with EXTSHM=ON.") \
\
- product(intx, AttachListenerTimeout, 1000, \
- "Timeout in ms the attach listener waits for a request") \
- range(0, 2147483) \
- \
/* Maximum expected size of the data segment. That correlates with the */ \
/* to the maximum C Heap consumption we expect. */ \
/* We need to know this because we need to leave "breathing space" for the */ \
--- a/src/hotspot/os/bsd/attachListener_bsd.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/os/bsd/attachListener_bsd.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -137,6 +137,10 @@
}
char* next() {
if (*_pos == '\0') {
+ // advance the iterator if possible (null arguments)
+ if (_pos < _end) {
+ _pos += 1;
+ }
return NULL;
}
char* res = _pos;
@@ -195,6 +199,7 @@
// bind socket
struct sockaddr_un addr;
+ memset((void *)&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, initial_path);
::unlink(initial_path);
@@ -260,6 +265,8 @@
do {
int n;
RESTARTABLE(read(s, buf+off, left), n);
+ assert(n <= left, "buffer was too small, impossible!");
+ buf[max_len - 1] = '\0';
if (n == -1) {
return NULL; // reset by peer or other error
}
@@ -342,10 +349,10 @@
}
// get the credentials of the peer and check the effective uid/guid
- // - check with jeff on this.
uid_t puid;
gid_t pgid;
if (::getpeereid(s, &puid, &pgid) != 0) {
+ log_debug(attach)("Failed to get peer id");
::close(s);
continue;
}
@@ -353,6 +360,7 @@
gid_t egid = getegid();
if (puid != euid || pgid != egid) {
+ log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", puid, pgid, euid, egid);
::close(s);
continue;
}
@@ -438,7 +446,6 @@
return op;
}
-
// Performs initialization at vm startup
// For BSD we remove any stale .java_pid file which could cause
// an attaching process to think we are ready to receive on the
@@ -497,7 +504,6 @@
char fn[PATH_MAX + 1];
int ret;
struct stat st;
-
snprintf(fn, PATH_MAX + 1, "%s/.attach_pid%d",
os::get_temp_directory(), os::current_process_id());
RESTARTABLE(::stat(fn, &st), ret);
@@ -509,7 +515,7 @@
// a bogus user creates the file
if (st.st_uid == geteuid()) {
init();
- log_trace(attach)("Attach trigerred by %s", fn);
+ log_trace(attach)("Attach triggered by %s", fn);
return true;
} else {
log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());
--- a/src/hotspot/os/linux/attachListener_linux.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/os/linux/attachListener_linux.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -138,6 +138,10 @@
}
char* next() {
if (*_pos == '\0') {
+ // advance the iterator if possible (null arguments)
+ if (_pos < _end) {
+ _pos += 1;
+ }
return NULL;
}
char* res = _pos;
@@ -196,6 +200,7 @@
// bind socket
struct sockaddr_un addr;
+ memset((void *)&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, initial_path);
::unlink(initial_path);
@@ -208,10 +213,10 @@
// put in listen mode, set permissions, and rename into place
res = ::listen(listener, 5);
if (res == 0) {
- RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res);
- if (res == 0) {
- res = ::rename(initial_path, path);
- }
+ RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res);
+ if (res == 0) {
+ res = ::rename(initial_path, path);
+ }
}
if (res == -1) {
::close(listener);
@@ -340,10 +345,10 @@
}
// get the credentials of the peer and check the effective uid/guid
- // - check with jeff on this.
struct ucred cred_info;
socklen_t optlen = sizeof(cred_info);
if (::getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void*)&cred_info, &optlen) == -1) {
+ log_debug(attach)("Failed to get socket option SO_PEERCRED");
::close(s);
continue;
}
@@ -351,6 +356,7 @@
gid_t egid = getegid();
if (cred_info.uid != euid || cred_info.gid != egid) {
+ log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", cred_info.uid, cred_info.gid, euid, egid);
::close(s);
continue;
}
@@ -436,7 +442,6 @@
return op;
}
-
// Performs initialization at vm startup
// For Linux we remove any stale .java_pid file which could cause
// an attaching process to think we are ready to receive on the
@@ -492,10 +497,10 @@
if (init_at_startup() || is_initialized()) {
return false; // initialized at startup or already initialized
}
- char fn[PATH_MAX+1];
- sprintf(fn, ".attach_pid%d", os::current_process_id());
+ char fn[PATH_MAX + 1];
int ret;
struct stat64 st;
+ sprintf(fn, ".attach_pid%d", os::current_process_id());
RESTARTABLE(::stat64(fn, &st), ret);
if (ret == -1) {
log_trace(attach)("Failed to find attach file: %s, trying alternate", fn);
@@ -511,10 +516,10 @@
// a bogus user creates the file
if (st.st_uid == geteuid()) {
init();
- log_trace(attach)("Attach trigerred by %s", fn);
+ log_trace(attach)("Attach triggered by %s", fn);
return true;
} else {
- log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not trigerred", fn, st.st_uid, geteuid());
+ log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());
}
}
return false;
--- a/src/hotspot/os/solaris/attachListener_solaris.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/os/solaris/attachListener_solaris.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -186,6 +186,10 @@
}
char* next() {
if (*_pos == '\0') {
+ // advance the iterator if possible (null arguments)
+ if (_pos < _end) {
+ _pos += 1;
+ }
return NULL;
}
char* res = _pos;
@@ -644,10 +648,10 @@
if (init_at_startup() || is_initialized()) {
return false; // initialized at startup or already initialized
}
- char fn[PATH_MAX+1];
- sprintf(fn, ".attach_pid%d", os::current_process_id());
+ char fn[PATH_MAX + 1];
int ret;
struct stat64 st;
+ sprintf(fn, ".attach_pid%d", os::current_process_id());
RESTARTABLE(::stat64(fn, &st), ret);
if (ret == -1) {
log_trace(attach)("Failed to find attach file: %s, trying alternate", fn);
@@ -663,7 +667,10 @@
// a bogus user creates the file
if (st.st_uid == geteuid()) {
init();
+ log_trace(attach)("Attach triggered by %s", fn);
return true;
+ } else {
+ log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());
}
}
return false;
--- a/src/hotspot/os/windows/attachListener_windows.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/os/windows/attachListener_windows.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -131,12 +131,12 @@
pipe_name_max = 256 // maximum pipe name
};
- char _pipe[pipe_name_max+1];
+ char _pipe[pipe_name_max + 1];
const char* pipe() const { return _pipe; }
void set_pipe(const char* pipe) {
- assert(strlen(pipe) <= pipe_name_max, "execeds maximum length of pipe name");
- strcpy(_pipe, pipe);
+ assert(strlen(pipe) <= pipe_name_max, "exceeds maximum length of pipe name");
+ os::snprintf(_pipe, sizeof(_pipe), "%s", pipe);
}
HANDLE open_pipe();
@@ -329,12 +329,20 @@
fSuccess = write_pipe(hPipe, msg, (int)strlen(msg));
if (fSuccess) {
- write_pipe(hPipe, (char*) result_stream->base(), (int)(result_stream->size()));
+ fSuccess = write_pipe(hPipe, (char*)result_stream->base(), (int)(result_stream->size()));
}
// Need to flush buffers
FlushFileBuffers(hPipe);
CloseHandle(hPipe);
+
+ if (fSuccess) {
+ log_debug(attach)("wrote result of attach operation %s to pipe %s", name(), pipe());
+ } else {
+ log_error(attach)("failure writing result of operation %s to pipe %s", name(), pipe());
+ }
+ } else {
+ log_error(attach)("could not open pipe %s to send result of operation %s", pipe(), name());
}
DWORD res = ::WaitForSingleObject(Win32AttachListener::mutex(), INFINITE);
--- a/src/hotspot/os/windows/os_windows.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/os/windows/os_windows.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -99,6 +99,8 @@
// for enumerating dll libraries
#include <vdmdbg.h>
#include <psapi.h>
+#include <mmsystem.h>
+#include <winsock2.h>
// for timer info max values which include all bits
#define ALL_64_BITS CONST64(-1)
--- a/src/hotspot/os_cpu/linux_arm/thread_linux_arm.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/os_cpu/linux_arm/thread_linux_arm.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -46,7 +46,7 @@
}
void JavaThread::cache_global_variables() {
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
const bool allow_shared_alloc =
Universe::heap()->supports_inline_contig_alloc();
--- a/src/hotspot/os_cpu/linux_sparc/vm_version_linux_sparc.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/os_cpu/linux_sparc/vm_version_linux_sparc.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -56,7 +56,7 @@
}
}
- ~CPUinfo() { os::free((void*)_string); }
+ ~CPUinfo() { free((void*)_string); }
const char* value() const { return _string; }
--- a/src/hotspot/share/c1/c1_LIRAssembler.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,7 +30,7 @@
#include "c1/c1_MacroAssembler.hpp"
#include "c1/c1_ValueStack.hpp"
#include "ci/ciInstance.hpp"
-#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/barrierSet.hpp"
#include "runtime/os.hpp"
void LIR_Assembler::patching_epilog(PatchingStub* patch, LIR_PatchCode patch_code, Register obj, CodeEmitInfo* info) {
@@ -100,7 +100,7 @@
LIR_Assembler::LIR_Assembler(Compilation* c):
_compilation(c)
, _masm(c->masm())
- , _bs(Universe::heap()->barrier_set())
+ , _bs(BarrierSet::barrier_set())
, _frame_map(c->frame_map())
, _current_block(NULL)
, _pending_non_safepoint(NULL)
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,6 +44,7 @@
#include "utilities/bitMap.inline.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
#endif // INCLUDE_ALL_GCS
#ifdef TRACE_HAVE_INTRINSICS
@@ -313,7 +314,7 @@
void LIRGenerator::init() {
- _bs = Universe::heap()->barrier_set();
+ _bs = BarrierSet::barrier_set();
}
@@ -1506,10 +1507,7 @@
}
LIR_Opr thrd = getThreadPointer();
LIR_Address* mark_active_flag_addr =
- new LIR_Address(thrd,
- in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active()),
- flag_type);
+ new LIR_Address(thrd, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), flag_type);
// Read the marking-in-progress flag.
LIR_Opr flag_val = new_register(T_INT);
__ load(mark_active_flag_addr, flag_val);
@@ -1659,9 +1657,11 @@
__ move(dirty, card_addr);
__ branch_destination(L_already_dirty->label());
} else {
+#if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
__ membar_storestore();
}
+#endif
__ move(dirty, card_addr);
}
#endif
--- a/src/hotspot/share/ci/ciInstanceKlass.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/ci/ciInstanceKlass.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -72,7 +72,7 @@
// by the GC but need to be strong roots if reachable from a current compilation.
// InstanceKlass are created for both weak and strong metadata. Ensuring this metadata
// alive covers the cases where there are weak roots without performance cost.
- oop holder = ik->klass_holder_phantom();
+ oop holder = ik->holder_phantom();
if (ik->is_anonymous()) {
// Though ciInstanceKlass records class loader oop, it's not enough to keep
// VM anonymous classes alive (loader == NULL). Klass holder should be used instead.
--- a/src/hotspot/share/ci/ciUtilities.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/ci/ciUtilities.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -51,7 +51,7 @@
// ------------------------------------------------------------------
// card_table_base
jbyte *ci_card_table_address() {
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust users of this code");
--- a/src/hotspot/share/classfile/altHashing.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/altHashing.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -27,6 +27,7 @@
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "oops/markOop.hpp"
+#include "oops/oop.inline.hpp"
#include "runtime/thread.hpp"
// Get the hash code of the classes mirror if it exists, otherwise just
--- a/src/hotspot/share/classfile/classFileParser.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/classFileParser.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -57,6 +57,7 @@
#include "oops/symbol.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiThreadState.hpp"
+#include "runtime/arguments.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/perfData.hpp"
@@ -89,6 +90,7 @@
#define JAVA_CLASSFILE_MAGIC 0xCAFEBABE
#define JAVA_MIN_SUPPORTED_VERSION 45
+#define JAVA_PREVIEW_MINOR_VERSION 65535
// Used for two backward compatibility reasons:
// - to check for new additions to the class file format in JDK1.5
@@ -4700,12 +4702,63 @@
(is_protected && is_private));
}
-static bool is_supported_version(u2 major, u2 minor){
+// A legal major_version.minor_version must be one of the following:
+//
+// Major_version = 45, any minor_version.
+// Major_version >= 46 and major_version <= current_major_version and minor_version = 0.
+// Major_version = current_major_version and minor_version = 65535 and --enable-preview is present.
+//
+static void verify_class_version(u2 major, u2 minor, Symbol* class_name, TRAPS){
const u2 max_version = JVM_CLASSFILE_MAJOR_VERSION;
- return (major >= JAVA_MIN_SUPPORTED_VERSION) &&
- (major <= max_version) &&
- ((major != max_version) ||
- (minor <= JVM_CLASSFILE_MINOR_VERSION));
+ if (major != JAVA_MIN_SUPPORTED_VERSION) { // All 45.* are ok including 45.65535
+ if (minor == JAVA_PREVIEW_MINOR_VERSION) {
+ if (major != max_version) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_UnsupportedClassVersionError(),
+ "%s (class file version %u.%u) was compiled with preview features that are unsupported. "
+ "This version of the Java Runtime only recognizes preview features for class file version %u.%u",
+ class_name->as_C_string(), major, minor, JVM_CLASSFILE_MAJOR_VERSION, JAVA_PREVIEW_MINOR_VERSION);
+ return;
+ }
+
+ if (!Arguments::enable_preview()) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_UnsupportedClassVersionError(),
+ "Preview features are not enabled for %s (class file version %u.%u). Try running with '--enable-preview'",
+ class_name->as_C_string(), major, minor);
+ return;
+ }
+
+ } else { // minor != JAVA_PREVIEW_MINOR_VERSION
+ if (major > max_version) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_UnsupportedClassVersionError(),
+ "%s has been compiled by a more recent version of the Java Runtime (class file version %u.%u), "
+ "this version of the Java Runtime only recognizes class file versions up to %u.0",
+ class_name->as_C_string(), major, minor, JVM_CLASSFILE_MAJOR_VERSION);
+ } else if (major < JAVA_MIN_SUPPORTED_VERSION) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_UnsupportedClassVersionError(),
+ "%s (class file version %u.%u) was compiled with an invalid major version",
+ class_name->as_C_string(), major, minor);
+ } else if (minor != 0) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_UnsupportedClassVersionError(),
+ "%s (class file version %u.%u) was compiled with an invalid non-zero minor version",
+ class_name->as_C_string(), major, minor);
+ }
+ }
+ }
}
void ClassFileParser::verify_legal_field_modifiers(jint flags,
@@ -5551,6 +5604,13 @@
ik->print_class_load_logging(_loader_data, module_name, _stream);
}
+ if (ik->minor_version() == JAVA_PREVIEW_MINOR_VERSION &&
+ ik->major_version() != JAVA_MIN_SUPPORTED_VERSION &&
+ log_is_enabled(Info, class, preview)) {
+ ResourceMark rm;
+ log_info(class, preview)("Loading preview feature type %s", ik->external_name());
+ }
+
if (log_is_enabled(Debug, class, resolve)) {
ResourceMark rm;
// print out the superclass.
@@ -5866,20 +5926,7 @@
}
// Check version numbers - we check this even with verifier off
- if (!is_supported_version(_major_version, _minor_version)) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_UnsupportedClassVersionError(),
- "%s has been compiled by a more recent version of the Java Runtime (class file version %u.%u), "
- "this version of the Java Runtime only recognizes class file versions up to %u.%u",
- _class_name->as_C_string(),
- _major_version,
- _minor_version,
- JVM_CLASSFILE_MAJOR_VERSION,
- JVM_CLASSFILE_MINOR_VERSION);
- return;
- }
+ verify_class_version(_major_version, _minor_version, _class_name, CHECK);
stream->guarantee_more(3, CHECK); // length, first cp tag
u2 cp_size = stream->get_u2_fast();
--- a/src/hotspot/share/classfile/classLoader.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/classLoader.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -148,6 +148,8 @@
#if INCLUDE_CDS
ClassPathEntry* ClassLoader::_app_classpath_entries = NULL;
ClassPathEntry* ClassLoader::_last_app_classpath_entry = NULL;
+ClassPathEntry* ClassLoader::_module_path_entries = NULL;
+ClassPathEntry* ClassLoader::_last_module_path_entry = NULL;
SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL;
#endif
@@ -721,7 +723,44 @@
}
}
-#endif
+void ClassLoader::add_to_module_path_entries(const char* path,
+ ClassPathEntry* entry) {
+ assert(entry != NULL, "ClassPathEntry should not be NULL");
+ assert(DumpSharedSpaces, "dump time only");
+
+ // The entry does not exist, add to the list
+ if (_module_path_entries == NULL) {
+ assert(_last_module_path_entry == NULL, "Sanity");
+ _module_path_entries = _last_module_path_entry = entry;
+ } else {
+ _last_module_path_entry->set_next(entry);
+ _last_module_path_entry = entry;
+ }
+}
+
+// Add a module path to the _module_path_entries list.
+void ClassLoader::update_module_path_entry_list(const char *path, TRAPS) {
+ assert(DumpSharedSpaces, "dump time only");
+ struct stat st;
+ int ret = os::stat(path, &st);
+ assert(ret == 0, "module path must exist");
+ // File or directory found
+ ClassPathEntry* new_entry = NULL;
+ new_entry = create_class_path_entry(path, &st, true /* throw_exception */,
+ false /*is_boot_append */, CHECK);
+ if (new_entry == NULL) {
+ return;
+ }
+
+ add_to_module_path_entries(path, new_entry);
+ return;
+}
+
+void ClassLoader::setup_module_search_path(const char* path, TRAPS) {
+ check_shared_classpath(path);
+ update_module_path_entry_list(path, THREAD);
+}
+#endif // INCLUDE_CDS
// Construct the array of module/path pairs as specified to --patch-module
// for the boot loader to search ahead of the jimage, if the class being
@@ -758,7 +797,6 @@
struct stat st;
if (os::stat(path, &st) == 0) {
// File or directory found
- Thread* THREAD = Thread::current();
ClassPathEntry* new_entry = create_class_path_entry(path, &st, false, false, CHECK);
// If the path specification is valid, enter it into this module's list
if (new_entry != NULL) {
@@ -828,7 +866,6 @@
struct stat st;
if (os::stat(path, &st) == 0) {
// Directory found
- Thread* THREAD = Thread::current();
ClassPathEntry* new_entry = create_class_path_entry(path, &st, false, false, CHECK);
// Check for a jimage
@@ -873,7 +910,7 @@
const char file_sep = os::file_separator()[0];
// 10 represents the length of "modules" + 2 file separators + \0
size_t len = strlen(home) + strlen(module_name) + 10;
- char *path = NEW_C_HEAP_ARRAY(char, len, mtModule);
+ char *path = NEW_RESOURCE_ARRAY(char, len);
jio_snprintf(path, len, "%s%cmodules%c%s", home, file_sep, file_sep, module_name);
struct stat st;
@@ -895,7 +932,6 @@
log_info(class, load)("path: %s", path);
}
}
- FREE_C_HEAP_ARRAY(char, path);
}
ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const struct stat* st,
@@ -1512,7 +1548,7 @@
}
#if INCLUDE_CDS
-static char* skip_uri_protocol(char* source) {
+char* ClassLoader::skip_uri_protocol(char* source) {
if (strncmp(source, "file:", 5) == 0) {
// file: protocol path could start with file:/ or file:///
// locate the char after all the forward slashes
@@ -1533,7 +1569,7 @@
// Record the shared classpath index and loader type for classes loaded
// by the builtin loaders at dump time.
-void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream) {
+void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS) {
assert(DumpSharedSpaces, "sanity");
assert(stream != NULL, "sanity");
@@ -1542,9 +1578,10 @@
return;
}
+ oop loader = ik->class_loader();
char* src = (char*)stream->source();
if (src == NULL) {
- if (ik->class_loader() == NULL) {
+ if (loader == NULL) {
// JFR classes
ik->set_shared_classpath_index(0);
ik->set_class_loader_type(ClassLoader::BOOT_LOADER);
@@ -1554,41 +1591,84 @@
assert(has_jrt_entry(), "CDS dumping does not support exploded JDK build");
- ModuleEntry* module = ik->module();
+ ResourceMark rm(THREAD);
int classpath_index = -1;
- ResourceMark rm;
- char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
+ PackageEntry* pkg_entry = ik->package();
+
+ if (FileMapInfo::get_number_of_shared_paths() > 0) {
+ char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
- // save the path from the file: protocol or the module name from the jrt: protocol
- // if no protocol prefix is found, path is the same as stream->source()
- char* path = skip_uri_protocol(src);
- for (int i = 0; i < FileMapInfo::get_number_of_share_classpaths(); i++) {
- SharedClassPathEntry* ent = FileMapInfo::shared_classpath(i);
- if (get_canonical_path(ent->name(), canonical_path, JVM_MAXPATHLEN)) {
- // If the path (from the class stream srouce) is the same as the shared
- // class path, then we have a match. For classes from module image loaded by the
- // PlatformClassLoader, the stream->source() is not the name of the module image.
- // Need to look for 'jrt:' explicitly.
- if (strcmp(canonical_path, os::native_path((char*)path)) == 0 ||
- (i == 0 && string_starts_with(src, "jrt:"))) {
- classpath_index = i;
- break;
+ // save the path from the file: protocol or the module name from the jrt: protocol
+ // if no protocol prefix is found, path is the same as stream->source()
+ char* path = skip_uri_protocol(src);
+ for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) {
+ SharedClassPathEntry* ent = FileMapInfo::shared_path(i);
+ if (get_canonical_path(ent->name(), canonical_path, JVM_MAXPATHLEN)) {
+ // If the path (from the class stream source) is the same as the shared
+ // class or module path, then we have a match.
+ if (strcmp(canonical_path, os::native_path((char*)path)) == 0) {
+ // NULL pkg_entry and pkg_entry in an unnamed module implies the class
+ // is from the -cp or boot loader append path which consists of -Xbootclasspath/a
+ // and jvmti appended entries.
+ if ((pkg_entry == NULL) || (pkg_entry->in_unnamed_module())) {
+ // Ensure the index is within the -cp range before assigning
+ // to the classpath_index.
+ if (SystemDictionary::is_system_class_loader(loader) &&
+ (i >= ClassLoaderExt::app_class_paths_start_index()) &&
+ (i < ClassLoaderExt::app_module_paths_start_index())) {
+ classpath_index = i;
+ break;
+ } else {
+ if ((i >= 1) &&
+ (i < ClassLoaderExt::app_class_paths_start_index())) {
+ // The class must be from boot loader append path which consists of
+ // -Xbootclasspath/a and jvmti appended entries.
+ assert(loader == NULL, "sanity");
+ classpath_index = i;
+ break;
+ }
+ }
+ } else {
+ // A class from a named module from the --module-path. Ensure the index is
+ // within the --module-path range before assigning to the classpath_index.
+ if ((pkg_entry != NULL) && !(pkg_entry->in_unnamed_module()) && (i > 0)) {
+ if (i >= ClassLoaderExt::app_module_paths_start_index() &&
+ i < FileMapInfo::get_number_of_shared_paths()) {
+ classpath_index = i;
+ break;
+ }
+ }
+ }
+ }
+ // for index 0 and the stream->source() is the modules image or has the jrt: protocol.
+ // The class must be from the runtime modules image.
+ if (i == 0 && (is_modules_image(src) || string_starts_with(src, "jrt:"))) {
+ classpath_index = i;
+ break;
+ }
}
}
- }
- if (classpath_index < 0) {
- // Shared classpath entry table only contains boot class path and -cp path.
+
// No path entry found for this class. Must be a shared class loaded by the
// user defined classloader.
- assert(ik->shared_classpath_index() < 0, "Sanity");
- return;
+ if (classpath_index < 0) {
+ assert(ik->shared_classpath_index() < 0, "Sanity");
+ return;
+ }
+ } else {
+ // The shared path table is set up after module system initialization.
+ // The path table contains no entry before that. Any classes loaded prior
+ // to the setup of the shared path table must be from the modules image.
+ assert(is_modules_image(src), "stream must be from modules image");
+ assert(FileMapInfo::get_number_of_shared_paths() == 0, "shared path table must not have been setup");
+ classpath_index = 0;
}
const char* const class_name = ik->name()->as_C_string();
const char* const file_name = file_name_for_class_name(class_name,
ik->name()->utf8_length());
assert(file_name != NULL, "invariant");
- Thread* THREAD = Thread::current();
+
ClassLoaderExt::Context context(class_name, file_name, CATCH);
context.record_result(ik->name(), classpath_index, ik, THREAD);
}
@@ -1673,6 +1753,13 @@
_shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
}
}
+
+void ClassLoader::initialize_module_path(TRAPS) {
+ if (DumpSharedSpaces) {
+ ClassLoaderExt::setup_module_paths(THREAD);
+ FileMapInfo::allocate_shared_path_table();
+ }
+}
#endif
jlong ClassLoader::classloader_time_ms() {
--- a/src/hotspot/share/classfile/classLoader.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/classLoader.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -238,12 +238,18 @@
CDS_ONLY(static ClassPathEntry* _app_classpath_entries;)
CDS_ONLY(static ClassPathEntry* _last_app_classpath_entry;)
- CDS_ONLY(static void setup_app_search_path(const char *class_path);)
+ CDS_ONLY(static ClassPathEntry* _module_path_entries;)
+ CDS_ONLY(static ClassPathEntry* _last_module_path_entry;)
+ CDS_ONLY(static void setup_app_search_path(const char* class_path);)
+ CDS_ONLY(static void setup_module_search_path(const char* path, TRAPS);)
static void add_to_app_classpath_entries(const char* path,
ClassPathEntry* entry,
bool check_for_duplicates);
+ CDS_ONLY(static void add_to_module_path_entries(const char* path,
+ ClassPathEntry* entry);)
public:
CDS_ONLY(static ClassPathEntry* app_classpath_entries() {return _app_classpath_entries;})
+ CDS_ONLY(static ClassPathEntry* module_path_entries() {return _module_path_entries;})
protected:
// Initialization:
@@ -286,6 +292,7 @@
bool check_for_duplicates,
bool is_boot_append,
bool throw_exception=true);
+ CDS_ONLY(static void update_module_path_entry_list(const char *path, TRAPS);)
static void print_bootclasspath();
// Timing
@@ -382,6 +389,7 @@
static void initialize();
static void classLoader_init2(TRAPS);
CDS_ONLY(static void initialize_shared_path();)
+ CDS_ONLY(static void initialize_module_path(TRAPS);)
static int compute_Object_vtable();
@@ -402,14 +410,28 @@
// entries during shared classpath setup time.
static int num_app_classpath_entries();
+ // Helper function used by CDS code to get the number of module path
+ // entries during shared classpath setup time.
+ static int num_module_path_entries() {
+ assert(DumpSharedSpaces, "Should only be called at CDS dump time");
+ int num_entries = 0;
+ ClassPathEntry* e= ClassLoader::_module_path_entries;
+ while (e != NULL) {
+ num_entries ++;
+ e = e->next();
+ }
+ return num_entries;
+ }
static void check_shared_classpath(const char *path);
static void finalize_shared_paths_misc_info();
static int get_shared_paths_misc_info_size();
static void* get_shared_paths_misc_info();
static bool check_shared_paths_misc_info(void* info, int size);
+ static int get_module_paths_misc_info_size();
+ static void* get_module_paths_misc_info();
static void exit_with_path_failure(const char* error, const char* message);
-
- static void record_result(InstanceKlass* ik, const ClassFileStream* stream);
+ static char* skip_uri_protocol(char* source);
+ static void record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS);
#endif
static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name,
const char* file_name, jlong &size);
--- a/src/hotspot/share/classfile/classLoaderData.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/classLoaderData.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -55,26 +55,22 @@
#include "classfile/moduleEntry.hpp"
#include "classfile/packageEntry.hpp"
#include "classfile/systemDictionary.hpp"
-#include "code/codeCache.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceShared.hpp"
-#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
+#include "memory/universe.hpp"
#include "oops/access.inline.hpp"
-#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
+#include "oops/weakHandle.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp"
-#include "runtime/javaCalls.hpp"
-#include "runtime/jniHandles.hpp"
#include "runtime/mutex.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/safepointVerifiers.hpp"
-#include "runtime/synchronizer.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
@@ -113,17 +109,21 @@
// The null-class-loader should always be kept alive.
_keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0),
_metaspace(NULL), _unloading(false), _klasses(NULL),
- _modules(NULL), _packages(NULL),
+ _modules(NULL), _packages(NULL), _unnamed_module(NULL), _dictionary(NULL),
_claimed(0), _modified_oops(true), _accumulated_modified_oops(false),
_jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
_next(NULL),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
Monitor::_safepoint_check_never)) {
- // A ClassLoaderData created solely for an anonymous class should never have a
- // ModuleEntryTable or PackageEntryTable created for it. The defining package
- // and module for an anonymous class will be found in its host class.
if (!is_anonymous) {
+ // The holder is initialized later for anonymous classes, and before calling anything
+ // that call class_loader().
+ initialize_holder(h_class_loader);
+
+ // A ClassLoaderData created solely for an anonymous class should never have a
+ // ModuleEntryTable or PackageEntryTable created for it. The defining package
+ // and module for an anonymous class will be found in its host class.
_packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size);
if (h_class_loader.is_null()) {
// Create unnamed module for boot loader
@@ -133,10 +133,6 @@
_unnamed_module = ModuleEntry::create_unnamed_module(this);
}
_dictionary = create_dictionary();
- } else {
- _packages = NULL;
- _unnamed_module = NULL;
- _dictionary = NULL;
}
NOT_PRODUCT(_dependency_count = 0); // number of class loader dependencies
@@ -510,6 +506,13 @@
}
+void ClassLoaderData::initialize_holder(Handle loader_or_mirror) {
+ if (loader_or_mirror() != NULL) {
+ assert(_holder.is_null(), "never replace holders");
+ _holder = WeakHandle<vm_class_loader_data>::create(loader_or_mirror);
+ }
+}
+
// Remove a klass from the _klasses list for scratch_class during redefinition
// or parsed class in the case of an error.
void ClassLoaderData::remove_class(Klass* scratch_class) {
@@ -611,30 +614,23 @@
}
// Tell the GC to keep this klass alive while iterating ClassLoaderDataGraph
-oop ClassLoaderData::holder_phantom() {
+oop ClassLoaderData::holder_phantom() const {
// A klass that was previously considered dead can be looked up in the
// CLD/SD, and its _java_mirror or _class_loader can be stored in a root
// or a reachable object making it alive again. The SATB part of G1 needs
// to get notified about this potential resurrection, otherwise the marking
// might not find the object.
- if (!keep_alive()) {
- oop* o = is_anonymous() ? _klasses->java_mirror_handle().ptr_raw() : &_class_loader;
- return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(o);
+ if (!_holder.is_null()) { // NULL class_loader
+ return _holder.resolve();
} else {
return NULL;
}
}
// Unloading support
-oop ClassLoaderData::keep_alive_object() const {
- assert_locked_or_safepoint(_metaspace_lock);
- assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive");
- return is_anonymous() ? _klasses->java_mirror() : class_loader();
-}
-
-bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
- bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
- || is_alive_closure->do_object_b(keep_alive_object());
+bool ClassLoaderData::is_alive() const {
+ bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
+ || (_holder.peek() != NULL); // not cleaned by weak reference processing
return alive;
}
@@ -668,6 +664,9 @@
ClassLoaderDataGraph::dec_array_classes(cl.array_class_released());
ClassLoaderDataGraph::dec_instance_classes(cl.instance_class_released());
+ // Release the WeakHandle
+ _holder.release();
+
// Release C heap allocated hashtable for all the packages.
if (_packages != NULL) {
// Destroy the table itself
@@ -969,7 +968,6 @@
ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous);
-
if (!is_anonymous) {
// First, Atomically set it
ClassLoaderData* old = java_lang_ClassLoader::cmpxchg_loader_data(cld, loader(), NULL);
@@ -1244,6 +1242,8 @@
ClassLoaderData* data = _head;
ClassLoaderData* prev = NULL;
bool seen_dead_loader = false;
+ uint loaders_processed = 0;
+ uint loaders_removed = 0;
// Mark metadata seen on the stack only so we can delete unneeded entries.
// Only walk all metadata, including the expensive code cache walk, for Full GC
@@ -1260,7 +1260,7 @@
data = _head;
while (data != NULL) {
- if (data->is_alive(is_alive_closure)) {
+ if (data->is_alive()) {
// clean metaspace
if (walk_all_metadata) {
data->classes_do(InstanceKlass::purge_previous_versions);
@@ -1268,9 +1268,11 @@
data->free_deallocate_list();
prev = data;
data = data->next();
+ loaders_processed++;
continue;
}
seen_dead_loader = true;
+ loaders_removed++;
ClassLoaderData* dead = data;
dead->unload();
data = data->next();
@@ -1313,6 +1315,8 @@
post_class_unload_events();
}
+ log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed);
+
return seen_dead_loader;
}
--- a/src/hotspot/share/classfile/classLoaderData.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/classLoaderData.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,6 +30,7 @@
#include "memory/metaspace.hpp"
#include "memory/metaspaceCounters.hpp"
#include "oops/oopHandle.hpp"
+#include "oops/weakHandle.hpp"
#include "runtime/mutex.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/growableArray.hpp"
@@ -113,7 +114,7 @@
static void packages_unloading_do(void f(PackageEntry*));
static void loaded_classes_do(KlassClosure* klass_closure);
static void classes_unloading_do(void f(Klass* const));
- static bool do_unloading(BoolObjectClosure* is_alive, bool clean_previous_versions);
+ static bool do_unloading(BoolObjectClosure* is_alive_closure, bool clean_previous_versions);
// dictionary do
// Iterate over all klasses in dictionary, but
@@ -219,8 +220,9 @@
static ClassLoaderData * _the_null_class_loader_data;
- oop _class_loader; // oop used to uniquely identify a class loader
- // class loader or a canonical class path
+ WeakHandle<vm_class_loader_data> _holder; // The oop that determines lifetime of this class loader
+ oop _class_loader; // The instance of java/lang/ClassLoader associated with
+ // this ClassLoaderData
ClassLoaderMetaspace * volatile _metaspace; // Meta-space where meta-data defined by the
// classes in the class loader are allocated.
@@ -286,7 +288,8 @@
void unload();
bool keep_alive() const { return _keep_alive > 0; }
- oop holder_phantom();
+
+ oop holder_phantom() const;
void classes_do(void f(Klass*));
void loaded_classes_do(KlassClosure* klass_closure);
void classes_do(void f(InstanceKlass*));
@@ -308,7 +311,7 @@
bool claimed() const { return _claimed == 1; }
bool claim();
- bool is_alive(BoolObjectClosure* is_alive_closure) const;
+ bool is_alive() const;
// Accessors
ClassLoaderMetaspace* metaspace_or_null() const { return _metaspace; }
@@ -348,7 +351,7 @@
// method will allocate a Metaspace if needed.
ClassLoaderMetaspace* metaspace_non_null();
- oop class_loader() const { return _class_loader; }
+ oop class_loader() const { return _class_loader; }
// The object the GC is using to keep this ClassLoaderData alive.
oop keep_alive_object() const;
@@ -364,6 +367,8 @@
void inc_keep_alive();
void dec_keep_alive();
+ void initialize_holder(Handle holder);
+
inline unsigned int identity_hash() const { return (unsigned int)(((intptr_t)this) >> 3); }
void oops_do(OopClosure* f, bool must_claim, bool clear_modified_oops = false);
--- a/src/hotspot/share/classfile/classLoaderExt.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,6 +30,7 @@
#include "classfile/classLoaderExt.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/klassFactory.hpp"
+#include "classfile/modules.hpp"
#include "classfile/sharedClassUtil.hpp"
#include "classfile/sharedPathsMiscInfo.hpp"
#include "classfile/systemDictionaryShared.hpp"
@@ -41,19 +42,21 @@
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "runtime/arguments.hpp"
+#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
#include "services/threadService.hpp"
#include "utilities/stringUtils.hpp"
-jshort ClassLoaderExt::_app_paths_start_index = ClassLoaderExt::max_classpath_index;
+jshort ClassLoaderExt::_app_class_paths_start_index = ClassLoaderExt::max_classpath_index;
+jshort ClassLoaderExt::_app_module_paths_start_index = ClassLoaderExt::max_classpath_index;
bool ClassLoaderExt::_has_app_classes = false;
bool ClassLoaderExt::_has_platform_classes = false;
void ClassLoaderExt::setup_app_search_path() {
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump and -XX:+UseAppCDS");
- _app_paths_start_index = ClassLoader::num_boot_classpath_entries();
+ _app_class_paths_start_index = ClassLoader::num_boot_classpath_entries();
char* app_class_path = os::strdup(Arguments::get_appclasspath());
if (strcmp(app_class_path, ".") == 0) {
@@ -68,6 +71,29 @@
}
}
+void ClassLoaderExt::process_module_table(ModuleEntryTable* met, TRAPS) {
+ ResourceMark rm;
+ for (int i = 0; i < met->table_size(); i++) {
+ for (ModuleEntry* m = met->bucket(i); m != NULL;) {
+ char* path = m->location()->as_C_string();
+ if (strncmp(path, "file:", 5) == 0 && ClassLoader::string_ends_with(path, ".jar")) {
+ m->print();
+ path = ClassLoader::skip_uri_protocol(path);
+ ClassLoader::setup_module_search_path(path, THREAD);
+ }
+ m = m->next();
+ }
+ }
+}
+void ClassLoaderExt::setup_module_search_path(TRAPS) {
+ assert(DumpSharedSpaces, "this function is only used with -Xshare:dump and -XX:+UseAppCDS");
+ _app_module_paths_start_index = ClassLoader::num_boot_classpath_entries() +
+ ClassLoader::num_app_classpath_entries();
+ Handle system_class_loader (THREAD, SystemDictionary::java_system_loader());
+ ModuleEntryTable* met = Modules::get_module_entry_table(system_class_loader);
+ process_module_table(met, THREAD);
+}
+
char* ClassLoaderExt::read_manifest(ClassPathEntry* entry, jint *manifest_size, bool clean_text, TRAPS) {
const char* name = "META-INF/MANIFEST.MF";
char* manifest;
@@ -195,6 +221,12 @@
}
}
+void ClassLoaderExt::setup_module_paths(TRAPS) {
+ if (UseAppCDS) {
+ ClassLoaderExt::setup_module_search_path(THREAD);
+ }
+}
+
Thread* ClassLoaderExt::Context::_dump_thread = NULL;
void ClassLoaderExt::record_result(ClassLoaderExt::Context *context,
--- a/src/hotspot/share/classfile/classLoaderExt.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/classLoaderExt.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -26,6 +26,7 @@
#define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
#include "classfile/classLoader.hpp"
+#include "classfile/moduleEntry.hpp"
#include "utilities/macros.hpp"
CDS_ONLY(class SharedPathsMiscInfoExt;)
@@ -59,14 +60,14 @@
_file_name = file_name;
#if INCLUDE_CDS
if (!DumpSharedSpaces && !UseSharedSpaces) {
- // Must not modify _app_paths_start_index if we're not using CDS.
- assert(_app_paths_start_index == ClassLoaderExt::max_classpath_index, "must be");
+ // Must not modify _app_class_paths_start_index if we're not using CDS.
+ assert(_app_class_paths_start_index == ClassLoaderExt::max_classpath_index, "must be");
}
#endif
}
bool should_verify(int classpath_index) {
- CDS_ONLY(return (classpath_index >= _app_paths_start_index);)
+ CDS_ONLY(return (classpath_index >= _app_class_paths_start_index);)
NOT_CDS(return false;)
}
@@ -82,8 +83,8 @@
~Context() {
#if INCLUDE_CDS
if (!DumpSharedSpaces && !UseSharedSpaces) {
- // Must not modify app_paths_start_index if we're not using CDS.
- assert(_app_paths_start_index == ClassLoaderExt::max_classpath_index, "must be");
+ // Must not modify app_class_paths_start_index if we're not using CDS.
+ assert(_app_class_paths_start_index == ClassLoaderExt::max_classpath_index, "must be");
}
#endif
}
@@ -93,10 +94,16 @@
#if INCLUDE_CDS
static char* get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size);
static void setup_app_search_path(); // Only when -Xshare:dump
+ static void process_module_table(ModuleEntryTable* met, TRAPS);
+ static void setup_module_search_path(TRAPS);
static SharedPathsMiscInfoExt* shared_paths_misc_info() {
return (SharedPathsMiscInfoExt*)_shared_paths_misc_info;
}
- static jshort _app_paths_start_index; // index of first app JAR in shared classpath entry table
+ // index of first app JAR in shared classpath entry table
+ static jshort _app_class_paths_start_index;
+ // index of first modular JAR in shared modulepath entry table
+ static jshort _app_module_paths_start_index;
+
static bool _has_app_classes;
static bool _has_platform_classes;
#endif
@@ -116,6 +123,7 @@
}
static void setup_search_paths() NOT_CDS_RETURN;
+ static void setup_module_paths(TRAPS) NOT_CDS_RETURN;
#if INCLUDE_CDS
private:
@@ -137,14 +145,20 @@
static void finalize_shared_paths_misc_info();
- static jshort app_paths_start_index() { return _app_paths_start_index; }
+ static jshort app_class_paths_start_index() { return _app_class_paths_start_index; }
+
+ static jshort app_module_paths_start_index() { return _app_module_paths_start_index; }
static void init_paths_start_index(jshort app_start) {
- _app_paths_start_index = app_start;
+ _app_class_paths_start_index = app_start;
+ }
+
+ static void init_app_module_paths_start_index(jshort module_start) {
+ _app_module_paths_start_index = module_start;
}
static bool is_boot_classpath(int classpath_index) {
- return classpath_index < _app_paths_start_index;
+ return classpath_index < _app_class_paths_start_index;
}
static bool has_platform_or_app_classes() {
--- a/src/hotspot/share/classfile/klassFactory.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/klassFactory.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -84,7 +84,7 @@
}
} else {
SharedClassPathEntry* ent =
- (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+ (SharedClassPathEntry*)FileMapInfo::shared_path(path_index);
pathname = ent == NULL ? NULL : ent->name();
}
ClassFileStream* stream = new ClassFileStream(ptr,
@@ -232,7 +232,7 @@
#if INCLUDE_CDS
if (DumpSharedSpaces) {
- ClassLoader::record_result(result, stream);
+ ClassLoader::record_result(result, stream, THREAD);
#if INCLUDE_JVMTI
assert(cached_class_file == NULL, "Sanity");
// Archive the class stream data into the optional data section
--- a/src/hotspot/share/classfile/modules.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/modules.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -85,7 +85,7 @@
return java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(version));
}
-static ModuleEntryTable* get_module_entry_table(Handle h_loader) {
+ModuleEntryTable* Modules::get_module_entry_table(Handle h_loader) {
// This code can be called during start-up, before the classLoader's classLoader data got
// created. So, call register_loader() to make sure the classLoader data gets created.
ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader);
--- a/src/hotspot/share/classfile/modules.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/modules.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,6 +28,7 @@
#include "memory/allocation.hpp"
#include "runtime/handles.hpp"
+class ModuleEntryTable;
class Symbol;
class Modules : AllStatic {
@@ -122,6 +123,7 @@
// Return TRUE iff package is defined by loader
static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS);
+ static ModuleEntryTable* get_module_entry_table(Handle h_loader);
};
#endif // SHARE_VM_CLASSFILE_MODULES_HPP
--- a/src/hotspot/share/classfile/sharedClassUtil.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/sharedClassUtil.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -93,6 +93,9 @@
case APP:
ClassLoader::trace_class_path("Expecting -Djava.class.path=", path);
break;
+ case MODULE:
+ ClassLoader::trace_class_path("Checking module path: ", path);
+ break;
default:
SharedPathsMiscInfo::print_path(out, type, path);
}
@@ -167,12 +170,13 @@
void SharedClassUtil::initialize(TRAPS) {
if (UseSharedSpaces) {
- int size = FileMapInfo::get_number_of_share_classpaths();
+ int size = FileMapInfo::get_number_of_shared_paths();
if (size > 0) {
SystemDictionaryShared::allocate_shared_data_arrays(size, THREAD);
if (!DumpSharedSpaces) {
FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header();
- ClassLoaderExt::init_paths_start_index(header->_app_paths_start_index);
+ ClassLoaderExt::init_paths_start_index(header->_app_class_paths_start_index);
+ ClassLoaderExt::init_app_module_paths_start_index(header->_app_module_paths_start_index);
}
}
}
@@ -208,7 +212,7 @@
bool SharedClassUtil::is_classpath_entry_signed(int classpath_index) {
assert(classpath_index >= 0, "Sanity");
SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*)
- FileMapInfo::shared_classpath(classpath_index);
+ FileMapInfo::shared_path(classpath_index);
return ent->_is_signed;
}
@@ -216,7 +220,8 @@
FileMapInfo::FileMapHeader::populate(mapinfo, alignment);
ClassLoaderExt::finalize_shared_paths_misc_info();
- _app_paths_start_index = ClassLoaderExt::app_paths_start_index();
+ _app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index();
+ _app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index();
_verify_local = BytecodeVerificationLocal;
_verify_remote = BytecodeVerificationRemote;
--- a/src/hotspot/share/classfile/sharedClassUtil.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/sharedClassUtil.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,10 +34,11 @@
class FileMapHeaderExt: public FileMapInfo::FileMapHeader {
public:
- jshort _app_paths_start_index; // Index of first app classpath entry
- bool _verify_local; // BytecodeVerificationLocal setting
- bool _verify_remote; // BytecodeVerificationRemote setting
- bool _has_platform_or_app_classes; // Archive contains app classes
+ jshort _app_class_paths_start_index; // Index of first app classpath entry
+ jshort _app_module_paths_start_index; // Index of first module path entry
+ bool _verify_local; // BytecodeVerificationLocal setting
+ bool _verify_remote; // BytecodeVerificationRemote setting
+ bool _has_platform_or_app_classes; // Archive contains app classes
FileMapHeaderExt() {
_has_platform_or_app_classes = true;
@@ -56,12 +57,14 @@
int _app_offset;
public:
enum {
- APP = 5
+ APP = 5,
+ MODULE = 6
};
virtual const char* type_name(int type) {
switch (type) {
case APP: return "APP";
+ case MODULE: return "MODULE";
default: return SharedPathsMiscInfo::type_name(type);
}
}
--- a/src/hotspot/share/classfile/stringTable.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/stringTable.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -45,7 +45,6 @@
#include "utilities/hashtable.inline.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
-#include "gc/g1/g1CollectedHeap.hpp"
#include "gc/g1/g1StringDedup.hpp"
#endif
--- a/src/hotspot/share/classfile/systemDictionary.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/systemDictionary.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,6 +44,7 @@
#include "code/codeCache.hpp"
#include "compiler/compileBroker.hpp"
#include "gc/shared/gcTraceTime.inline.hpp"
+#include "gc/shared/oopStorage.inline.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/interpreter.hpp"
#include "logging/log.hpp"
@@ -117,6 +118,8 @@
const int defaultProtectionDomainCacheSize = 1009;
+OopStorage* SystemDictionary::_vm_weak_oop_storage = NULL;
+
// ----------------------------------------------------------------------------
// Java-level SystemLoader and PlatformLoader
@@ -1012,7 +1015,9 @@
CHECK_NULL);
if (host_klass != NULL && k != NULL) {
- // If it's anonymous, initialize it now, since nobody else will.
+ // Anonymous classes must update ClassLoaderData holder (was host_klass loader)
+ // so that they can be unloaded when the mirror is no longer referenced.
+ k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
{
MutexLocker mu_r(Compile_lock, THREAD);
@@ -1032,6 +1037,8 @@
if (cp_patches != NULL) {
k->constants()->patch_resolved_references(cp_patches);
}
+
+ // If it's anonymous, initialize it now, since nobody else will.
k->eager_initialize(CHECK_NULL);
// notify jvmti
@@ -1210,7 +1217,7 @@
}
}
SharedClassPathEntry* ent =
- (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+ (SharedClassPathEntry*)FileMapInfo::shared_path(path_index);
if (!Universe::is_module_initialized()) {
assert(ent != NULL && ent->is_modules_image(),
"Loading non-bootstrap classes before the module system is initialized");
@@ -1848,6 +1855,10 @@
GCTimer* gc_timer,
bool do_cleaning) {
+ {
+ GCTraceTime(Debug, gc, phases) t("SystemDictionary WeakHandle cleaning", gc_timer);
+ vm_weak_oop_storage()->weak_oops_do(is_alive, &do_nothing_cl);
+ }
bool unloading_occurred;
{
@@ -1896,9 +1907,11 @@
// Only the protection domain oops contain references into the heap. Iterate
// over all of them.
_pd_cache_table->oops_do(strong);
+ vm_weak_oop_storage()->oops_do(strong);
} else {
if (weak != NULL) {
_pd_cache_table->oops_do(weak);
+ vm_weak_oop_storage()->oops_do(weak);
}
}
@@ -1924,6 +1937,8 @@
invoke_method_table()->oops_do(f);
ResolvedMethodTable::oops_do(f);
+
+ vm_weak_oop_storage()->oops_do(f);
}
// CDS: scan and relocate all classes in the system dictionary.
@@ -3105,3 +3120,15 @@
return (loader_data->class_loader() == NULL ? "<bootloader>" :
SystemDictionary::loader_name(loader_data->class_loader()));
}
+
+void SystemDictionary::initialize_oop_storage() {
+ _vm_weak_oop_storage =
+ new OopStorage("VM Weak Oop Handles",
+ VMWeakAlloc_lock,
+ VMWeakActive_lock);
+}
+
+OopStorage* SystemDictionary::vm_weak_oop_storage() {
+ assert(_vm_weak_oop_storage != NULL, "Uninitialized");
+ return _vm_weak_oop_storage;
+}
--- a/src/hotspot/share/classfile/systemDictionary.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/systemDictionary.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -84,6 +84,7 @@
class ProtectionDomainCacheTable;
class ProtectionDomainCacheEntry;
class GCTimer;
+class OopStorage;
// Certain classes are preloaded, such as java.lang.Object and java.lang.String.
// They are all "well-known", in the sense that no class loader is allowed
@@ -637,6 +638,9 @@
// ProtectionDomain cache
static ProtectionDomainCacheTable* _pd_cache_table;
+ // VM weak OopStorage object.
+ static OopStorage* _vm_weak_oop_storage;
+
protected:
static void validate_protection_domain(InstanceKlass* klass,
Handle class_loader,
@@ -689,6 +693,9 @@
return !m->is_public() && m->method_holder() == SystemDictionary::Object_klass();
}
+ static void initialize_oop_storage();
+ static OopStorage* vm_weak_oop_storage();
+
protected:
static InstanceKlass* find_shared_class(Symbol* class_name);
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -92,7 +92,7 @@
Handle empty;
Handle manifest ;
if (shared_jar_manifest(shared_path_index) == NULL) {
- SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*)FileMapInfo::shared_classpath(shared_path_index);
+ SharedClassPathEntryExt* ent = (SharedClassPathEntryExt*)FileMapInfo::shared_path(shared_path_index);
long size = ent->manifest_size();
if (size <= 0) {
return empty; // No manifest - return NULL handle
@@ -138,7 +138,7 @@
Handle url_h;
if (shared_jar_url(shared_path_index) == NULL) {
JavaValue result(T_OBJECT);
- const char* path = FileMapInfo::shared_classpath_name(shared_path_index);
+ const char* path = FileMapInfo::shared_path_name(shared_path_index);
Handle path_string = java_lang_String::create_from_str(path, CHECK_(url_h));
Klass* classLoaders_klass =
SystemDictionary::jdk_internal_loader_ClassLoaders_klass();
@@ -304,7 +304,7 @@
int index = ik->shared_classpath_index();
assert(index >= 0, "Sanity");
SharedClassPathEntryExt* ent =
- (SharedClassPathEntryExt*)FileMapInfo::shared_classpath(index);
+ (SharedClassPathEntryExt*)FileMapInfo::shared_path(index);
Symbol* class_name = ik->name();
if (ent->is_modules_image()) {
@@ -328,13 +328,13 @@
// For shared app/platform classes originated from JAR files on the class path:
// Each of the 3 SystemDictionaryShared::_shared_xxx arrays has the same length
// as the shared classpath table in the shared archive (see
- // FileMap::_classpath_entry_table in filemap.hpp for details).
+ // FileMap::_shared_path_table in filemap.hpp for details).
//
// If a shared InstanceKlass k is loaded from the class path, let
//
// index = k->shared_classpath_index():
//
- // FileMap::_classpath_entry_table[index] identifies the JAR file that contains k.
+ // FileMap::_shared_path_table[index] identifies the JAR file that contains k.
//
// k's protection domain is:
//
@@ -358,9 +358,7 @@
}
// Currently AppCDS only archives classes from the run-time image, the
-// -Xbootclasspath/a path, and the class path. The following rules need to be
-// revised when AppCDS is changed to archive classes from other code sources
-// in the future, for example the module path (specified by -p).
+// -Xbootclasspath/a path, the class path, and the module path.
//
// Check if a shared class can be loaded by the specific classloader. Following
// are the "visible" archived classes for different classloaders.
@@ -368,10 +366,10 @@
// NULL classloader:
// - see SystemDictionary::is_shared_class_visible()
// Platform classloader:
-// - Module class from "modules" jimage. ModuleEntry must be defined in the
+// - Module class from runtime image. ModuleEntry must be defined in the
// classloader.
-// App Classloader:
-// - Module class from "modules" jimage. ModuleEntry must be defined in the
+// App classloader:
+// - Module Class from runtime image and module path. ModuleEntry must be defined in the
// classloader.
// - Class from -cp. The class must have no PackageEntry defined in any of the
// boot/platform/app classloader, or must be in the unnamed module defined in the
@@ -386,10 +384,11 @@
TRAPS) {
assert(class_loader.not_null(), "Class loader should not be NULL");
assert(Universe::is_module_initialized(), "Module system is not initialized");
+ ResourceMark rm(THREAD);
int path_index = ik->shared_classpath_index();
SharedClassPathEntry* ent =
- (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+ (SharedClassPathEntry*)FileMapInfo::shared_path(path_index);
if (SystemDictionary::is_platform_class_loader(class_loader())) {
assert(ent != NULL, "shared class for PlatformClassLoader should have valid SharedClassPathEntry");
@@ -400,7 +399,7 @@
// PackageEntry/ModuleEntry is found in the classloader. Check if the
// ModuleEntry's location agrees with the archived class' origination.
if (ent->is_modules_image() && mod_entry->location()->starts_with("jrt:")) {
- return true; // Module class from the "modules" jimage
+ return true; // Module class from the runtime image
}
}
} else if (SystemDictionary::is_system_class_loader(class_loader())) {
@@ -409,7 +408,8 @@
// The archived class is in the unnamed package. Currently, the boot image
// does not contain any class in the unnamed package.
assert(!ent->is_modules_image(), "Class in the unnamed package must be from the classpath");
- if (path_index >= ClassLoaderExt::app_paths_start_index()) {
+ if (path_index >= ClassLoaderExt::app_class_paths_start_index()) {
+ assert(path_index < ClassLoaderExt::app_module_paths_start_index(), "invalid path_index");
return true;
}
} else {
@@ -421,23 +421,37 @@
if (get_package_entry(pkg_name, ClassLoaderData::class_loader_data_or_null(SystemDictionary::java_platform_loader())) == NULL &&
get_package_entry(pkg_name, ClassLoaderData::the_null_class_loader_data()) == NULL) {
// The PackageEntry is not defined in any of the boot/platform/app classloaders.
- // The archived class must from -cp path and not from the run-time image.
- if (!ent->is_modules_image() && path_index >= ClassLoaderExt::app_paths_start_index()) {
+ // The archived class must from -cp path and not from the runtime image.
+ if (!ent->is_modules_image() && path_index >= ClassLoaderExt::app_class_paths_start_index() &&
+ path_index < ClassLoaderExt::app_module_paths_start_index()) {
return true;
}
}
} else if (mod_entry != NULL) {
- // The package/module is defined in the AppClassLoader. Currently we only
- // support archiving application module class from the run-time image.
+ // The package/module is defined in the AppClassLoader. We support
+ // archiving application module class from the runtime image or from
+ // a named module from a module path.
// Packages from the -cp path are in the unnamed_module.
- if ((ent->is_modules_image() && mod_entry->location()->starts_with("jrt:")) ||
- (pkg_entry->in_unnamed_module() && path_index >= ClassLoaderExt::app_paths_start_index())) {
+ if (ent->is_modules_image() && mod_entry->location()->starts_with("jrt:")) {
+ // shared module class from runtime image
+ return true;
+ } else if (pkg_entry->in_unnamed_module() && path_index >= ClassLoaderExt::app_class_paths_start_index() &&
+ path_index < ClassLoaderExt::app_module_paths_start_index()) {
+ // shared class from -cp
DEBUG_ONLY( \
ClassLoaderData* loader_data = class_loader_data(class_loader); \
- if (pkg_entry->in_unnamed_module()) \
- assert(mod_entry == loader_data->unnamed_module(), "the unnamed module is not defined in the classloader");)
-
+ assert(mod_entry == loader_data->unnamed_module(), "the unnamed module is not defined in the classloader");)
return true;
+ } else {
+ if(!pkg_entry->in_unnamed_module() &&
+ (path_index >= ClassLoaderExt::app_module_paths_start_index())&&
+ (path_index < FileMapInfo::get_number_of_shared_paths()) &&
+ (strcmp(ent->name(), ClassLoader::skip_uri_protocol(mod_entry->location()->as_C_string())) == 0)) {
+ // shared module class from module path
+ return true;
+ } else {
+ assert(path_index < FileMapInfo::get_number_of_shared_paths(), "invalid path_index");
+ }
}
}
}
--- a/src/hotspot/share/code/codeCache.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/code/codeCache.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -51,6 +51,7 @@
#include "runtime/mutexLocker.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/sweeper.hpp"
+#include "runtime/vmThread.hpp"
#include "services/memoryService.hpp"
#include "trace/tracing.hpp"
#include "utilities/align.hpp"
--- a/src/hotspot/share/code/relocInfo_ext.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/code/relocInfo_ext.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -59,7 +59,7 @@
return (address)Universe::heap()->end_addr();
}
case symbolic_Relocation::card_table_reference: {
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
CardTable* ct = ctbs->card_table();
return (address)ct->byte_map_base();
--- a/src/hotspot/share/compiler/disassembler.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/compiler/disassembler.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -318,7 +318,7 @@
return;
}
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->is_a(BarrierSet::CardTableBarrierSet) &&
adr == ci_card_table_address_as<address>()) {
st->print("word_map_base");
--- a/src/hotspot/share/gc/cms/adaptiveFreeList.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/adaptiveFreeList.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -26,6 +26,7 @@
#include "gc/cms/adaptiveFreeList.hpp"
#include "gc/cms/freeChunk.hpp"
#include "gc/shared/collectedHeap.hpp"
+#include "memory/freeList.inline.hpp"
#include "runtime/globals.hpp"
#include "runtime/mutex.hpp"
#include "runtime/orderAccess.inline.hpp"
--- a/src/hotspot/share/gc/cms/cmsArguments.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/cmsArguments.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -82,9 +82,36 @@
// certainly gain from analysis of platform and environment.
void CMSArguments::initialize() {
GCArguments::initialize();
+
assert(!UseSerialGC && !UseParallelOldGC && !UseParallelGC, "Error");
assert(UseConcMarkSweepGC, "CMS is expected to be on here");
+ // CMS space iteration, which FLSVerifyAllHeapreferences entails,
+ // insists that we hold the requisite locks so that the iteration is
+ // MT-safe. For the verification at start-up and shut-down, we don't
+ // yet have a good way of acquiring and releasing these locks,
+ // which are not visible at the CollectedHeap level. We want to
+ // be able to acquire these locks and then do the iteration rather
+ // than just disable the lock verification. This will be fixed under
+ // bug 4788986.
+ if (UseConcMarkSweepGC && FLSVerifyAllHeapReferences) {
+ if (VerifyDuringStartup) {
+ warning("Heap verification at start-up disabled "
+ "(due to current incompatibility with FLSVerifyAllHeapReferences)");
+ VerifyDuringStartup = false; // Disable verification at start-up
+ }
+
+ if (VerifyBeforeExit) {
+ warning("Heap verification at shutdown disabled "
+ "(due to current incompatibility with FLSVerifyAllHeapReferences)");
+ VerifyBeforeExit = false; // Disable verification at shutdown
+ }
+ }
+
+ if (!ClassUnloading) {
+ FLAG_SET_CMDLINE(bool, CMSClassUnloadingEnabled, false);
+ }
+
// Set CMS global values
CompactibleFreeListSpace::set_cms_values();
--- a/src/hotspot/share/gc/cms/cmsCardTable.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/cmsCardTable.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "gc/cms/cmsCardTable.hpp"
#include "gc/cms/cmsHeap.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
#include "gc/shared/cardTableRS.hpp"
@@ -36,7 +37,24 @@
#include "runtime/orderAccess.inline.hpp"
#include "runtime/vmThread.hpp"
-void CardTableRS::
+CMSCardTable::CMSCardTable(MemRegion whole_heap) :
+ CardTableRS(whole_heap, CMSPrecleaningEnabled /* scanned_concurrently */) {
+}
+
+// Returns the number of chunks necessary to cover "mr".
+size_t CMSCardTable::chunks_to_cover(MemRegion mr) {
+ return (size_t)(addr_to_chunk_index(mr.last()) -
+ addr_to_chunk_index(mr.start()) + 1);
+}
+
+// Returns the index of the chunk in a stride which
+// covers the given address.
+uintptr_t CMSCardTable::addr_to_chunk_index(const void* addr) {
+ uintptr_t card = (uintptr_t) byte_for(addr);
+ return card / ParGCCardsPerStrideChunk;
+}
+
+void CMSCardTable::
non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
OopsInGenClosure* cl,
CardTableRS* ct,
@@ -82,7 +100,7 @@
}
void
-CardTableRS::
+CMSCardTable::
process_stride(Space* sp,
MemRegion used,
jint stride, int n_strides,
@@ -162,7 +180,7 @@
}
void
-CardTableRS::
+CMSCardTable::
process_chunk_boundaries(Space* sp,
DirtyCardToOopClosure* dcto_cl,
MemRegion chunk_mr,
@@ -371,7 +389,7 @@
}
void
-CardTableRS::
+CMSCardTable::
get_LNC_array_for_space(Space* sp,
jbyte**& lowest_non_clean,
uintptr_t& lowest_non_clean_base_chunk_index,
@@ -430,3 +448,26 @@
lowest_non_clean_base_chunk_index = _lowest_non_clean_base_chunk_index[i];
lowest_non_clean_chunk_size = _lowest_non_clean_chunk_size[i];
}
+
+#ifdef ASSERT
+void CMSCardTable::verify_used_region_at_save_marks(Space* sp) const {
+ MemRegion ur = sp->used_region();
+ MemRegion urasm = sp->used_region_at_save_marks();
+
+ if (!ur.contains(urasm)) {
+ log_warning(gc)("CMS+ParNew: Did you forget to call save_marks()? "
+ "[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in "
+ "[" PTR_FORMAT ", " PTR_FORMAT ")",
+ p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end()));
+ MemRegion ur2 = sp->used_region();
+ MemRegion urasm2 = sp->used_region_at_save_marks();
+ if (!ur.equals(ur2)) {
+ log_warning(gc)("CMS+ParNew: Flickering used_region()!!");
+ }
+ if (!urasm.equals(urasm2)) {
+ log_warning(gc)("CMS+ParNew: Flickering used_region_at_save_marks()!!");
+ }
+ ShouldNotReachHere();
+ }
+}
+#endif // ASSERT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/cms/cmsCardTable.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_CMS_CMSCARDTABLE_HPP
+#define SHARE_GC_CMS_CMSCARDTABLE_HPP
+
+#include "gc/shared/cardTableRS.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class DirtyCardToOopClosure;
+class MemRegion;
+class OopsInGenClosure;
+class Space;
+
+class CMSCardTable : public CardTableRS {
+private:
+ // Returns the number of chunks necessary to cover "mr".
+ size_t chunks_to_cover(MemRegion mr);
+
+ // Returns the index of the chunk in a stride which
+ // covers the given address.
+ uintptr_t addr_to_chunk_index(const void* addr);
+
+ // Initializes "lowest_non_clean" to point to the array for the region
+ // covering "sp", and "lowest_non_clean_base_chunk_index" to the chunk
+ // index of the corresponding to the first element of that array.
+ // Ensures that these arrays are of sufficient size, allocating if necessary.
+ // May be called by several threads concurrently.
+ void get_LNC_array_for_space(Space* sp,
+ jbyte**& lowest_non_clean,
+ uintptr_t& lowest_non_clean_base_chunk_index,
+ size_t& lowest_non_clean_chunk_size);
+
+ // Apply cl, which must either itself apply dcto_cl or be dcto_cl,
+ // to the cards in the stride (of n_strides) within the given space.
+ void process_stride(Space* sp,
+ MemRegion used,
+ jint stride, int n_strides,
+ OopsInGenClosure* cl,
+ CardTableRS* ct,
+ jbyte** lowest_non_clean,
+ uintptr_t lowest_non_clean_base_chunk_index,
+ size_t lowest_non_clean_chunk_size);
+
+ // Makes sure that chunk boundaries are handled appropriately, by
+ // adjusting the min_done of dcto_cl, and by using a special card-table
+ // value to indicate how min_done should be set.
+ void process_chunk_boundaries(Space* sp,
+ DirtyCardToOopClosure* dcto_cl,
+ MemRegion chunk_mr,
+ MemRegion used,
+ jbyte** lowest_non_clean,
+ uintptr_t lowest_non_clean_base_chunk_index,
+ size_t lowest_non_clean_chunk_size);
+
+ virtual void verify_used_region_at_save_marks(Space* sp) const NOT_DEBUG_RETURN;
+
+protected:
+ // Work method used to implement non_clean_card_iterate_possibly_parallel()
+ // above in the parallel case.
+ virtual void non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
+ OopsInGenClosure* cl, CardTableRS* ct,
+ uint n_threads);
+
+public:
+ CMSCardTable(MemRegion whole_heap);
+};
+
+#endif // SHARE_GC_CMS_CMSCARDTABLE_HPP
--- a/src/hotspot/share/gc/cms/cmsCollectorPolicy.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/cmsCollectorPolicy.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,7 +30,6 @@
#include "gc/shared/collectorPolicy.hpp"
#include "gc/shared/gcLocker.hpp"
#include "gc/shared/gcPolicyCounters.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/generationSpec.hpp"
#include "gc/shared/space.hpp"
#include "gc/shared/vmGCOperations.hpp"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/cms/cmsGCStats.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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/cms/cmsGCStats.hpp"
+#include "gc/shared/gcUtil.inline.hpp"
+#include "runtime/globals.hpp"
+
+CMSGCStats::CMSGCStats() {
+ _avg_promoted = new AdaptivePaddedNoZeroDevAverage(
+ CMSExpAvgFactor,
+ PromotedPadding);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/cms/cmsGCStats.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_CMS_CMSGCSTATS_HPP
+#define SHARE_GC_CMS_CMSGCSTATS_HPP
+
+#include "gc/shared/gcStats.hpp"
+
+class CMSGCStats : public GCStats {
+ public:
+ CMSGCStats();
+
+ virtual Name kind() {
+ return CMSGCStatsKind;
+ }
+};
+
+#endif // SHARE_GC_CMS_CMSGCSTATS_HPP
--- a/src/hotspot/share/gc/cms/cmsHeap.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/cmsHeap.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,12 +23,14 @@
*/
#include "precompiled.hpp"
+#include "gc/cms/cmsCardTable.hpp"
#include "gc/cms/compactibleFreeListSpace.hpp"
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
#include "gc/cms/concurrentMarkSweepThread.hpp"
#include "gc/cms/cmsHeap.hpp"
#include "gc/cms/parNewGeneration.hpp"
#include "gc/cms/vmCMSOperations.hpp"
+#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/genMemoryPools.hpp"
#include "gc/shared/genOopClosures.inline.hpp"
#include "gc/shared/strongRootsScope.hpp"
@@ -90,6 +92,10 @@
return JNI_OK;
}
+CardTableRS* CMSHeap::create_rem_set(const MemRegion& reserved_region) {
+ return new CMSCardTable(reserved_region);
+}
+
void CMSHeap::initialize_serviceability() {
_young_manager = new GCMemoryManager("ParNew", "end of minor GC");
_old_manager = new GCMemoryManager("ConcurrentMarkSweep", "end of major GC");
--- a/src/hotspot/share/gc/cms/cmsHeap.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/cmsHeap.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -51,6 +51,7 @@
// Returns JNI_OK on success
virtual jint initialize();
+ virtual CardTableRS* create_rem_set(const MemRegion& reserved_region);
// Convenience function to be used in situations where the heap type can be
// asserted to be this type.
--- a/src/hotspot/share/gc/cms/cmsOopClosures.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/cmsOopClosures.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "gc/cms/cmsOopClosures.inline.hpp"
-#include "gc/shared/specialized_oop_closures.hpp"
+#include "gc/cms/cms_specialized_oop_closures.hpp"
#include "memory/iterator.inline.hpp"
// Generate CMS specialized oop_oop_iterate functions.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/cms/cms_globals.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_CMS_CMS_GLOBALS_HPP
+#define SHARE_GC_CMS_CMS_GLOBALS_HPP
+
+#define GC_CMS_FLAGS(develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+ product(bool, UseCMSBestFit, true, \
+ "Use CMS best fit allocation strategy") \
+ \
+ product(size_t, CMSOldPLABMax, 1024, \
+ "Maximum size of CMS gen promotion LAB caches per worker " \
+ "per block size") \
+ range(1, max_uintx) \
+ constraint(CMSOldPLABMaxConstraintFunc,AfterMemoryInit) \
+ \
+ product(size_t, CMSOldPLABMin, 16, \
+ "Minimum size of CMS gen promotion LAB caches per worker " \
+ "per block size") \
+ range(1, max_uintx) \
+ constraint(CMSOldPLABMinConstraintFunc,AfterMemoryInit) \
+ \
+ product(uintx, CMSOldPLABNumRefills, 4, \
+ "Nominal number of refills of CMS gen promotion LAB cache " \
+ "per worker per block size") \
+ range(1, max_uintx) \
+ \
+ product(bool, CMSOldPLABResizeQuicker, false, \
+ "React on-the-fly during a scavenge to a sudden " \
+ "change in block demand rate") \
+ \
+ product(uintx, CMSOldPLABToleranceFactor, 4, \
+ "The tolerance of the phase-change detector for on-the-fly " \
+ "PLAB resizing during a scavenge") \
+ range(1, max_uintx) \
+ \
+ product(uintx, CMSOldPLABReactivityFactor, 2, \
+ "The gain in the feedback loop for on-the-fly PLAB resizing " \
+ "during a scavenge") \
+ range(1, max_uintx) \
+ \
+ product_pd(size_t, CMSYoungGenPerWorker, \
+ "The maximum size of young gen chosen by default per GC worker " \
+ "thread available") \
+ range(1, max_uintx) \
+ \
+ product(uintx, CMSIncrementalSafetyFactor, 10, \
+ "Percentage (0-100) used to add conservatism when computing the " \
+ "duty cycle") \
+ range(0, 100) \
+ \
+ product(uintx, CMSExpAvgFactor, 50, \
+ "Percentage (0-100) used to weight the current sample when " \
+ "computing exponential averages for CMS statistics") \
+ range(0, 100) \
+ \
+ product(uintx, CMS_FLSWeight, 75, \
+ "Percentage (0-100) used to weight the current sample when " \
+ "computing exponentially decaying averages for CMS FLS " \
+ "statistics") \
+ range(0, 100) \
+ \
+ product(uintx, CMS_FLSPadding, 1, \
+ "The multiple of deviation from mean to use for buffering " \
+ "against volatility in free list demand") \
+ range(0, max_juint) \
+ \
+ product(uintx, FLSCoalescePolicy, 2, \
+ "CMS: aggressiveness level for coalescing, increasing " \
+ "from 0 to 4") \
+ range(0, 4) \
+ \
+ product(bool, FLSAlwaysCoalesceLarge, false, \
+ "CMS: larger free blocks are always available for coalescing") \
+ \
+ product(double, FLSLargestBlockCoalesceProximity, 0.99, \
+ "CMS: the smaller the percentage the greater the coalescing " \
+ "force") \
+ range(0.0, 1.0) \
+ \
+ product(double, CMSSmallCoalSurplusPercent, 1.05, \
+ "CMS: the factor by which to inflate estimated demand of small " \
+ "block sizes to prevent coalescing with an adjoining block") \
+ range(0.0, DBL_MAX) \
+ \
+ product(double, CMSLargeCoalSurplusPercent, 0.95, \
+ "CMS: the factor by which to inflate estimated demand of large " \
+ "block sizes to prevent coalescing with an adjoining block") \
+ range(0.0, DBL_MAX) \
+ \
+ product(double, CMSSmallSplitSurplusPercent, 1.10, \
+ "CMS: the factor by which to inflate estimated demand of small " \
+ "block sizes to prevent splitting to supply demand for smaller " \
+ "blocks") \
+ range(0.0, DBL_MAX) \
+ \
+ product(double, CMSLargeSplitSurplusPercent, 1.00, \
+ "CMS: the factor by which to inflate estimated demand of large " \
+ "block sizes to prevent splitting to supply demand for smaller " \
+ "blocks") \
+ range(0.0, DBL_MAX) \
+ \
+ product(bool, CMSExtrapolateSweep, false, \
+ "CMS: cushion for block demand during sweep") \
+ \
+ product(uintx, CMS_SweepWeight, 75, \
+ "Percentage (0-100) used to weight the current sample when " \
+ "computing exponentially decaying average for inter-sweep " \
+ "duration") \
+ range(0, 100) \
+ \
+ product(uintx, CMS_SweepPadding, 1, \
+ "The multiple of deviation from mean to use for buffering " \
+ "against volatility in inter-sweep duration") \
+ range(0, max_juint) \
+ \
+ product(uintx, CMS_SweepTimerThresholdMillis, 10, \
+ "Skip block flux-rate sampling for an epoch unless inter-sweep " \
+ "duration exceeds this threshold in milliseconds") \
+ range(0, max_uintx) \
+ \
+ product(bool, CMSClassUnloadingEnabled, true, \
+ "Whether class unloading enabled when using CMS GC") \
+ \
+ product(uintx, CMSClassUnloadingMaxInterval, 0, \
+ "When CMS class unloading is enabled, the maximum CMS cycle " \
+ "count for which classes may not be unloaded") \
+ range(0, max_uintx) \
+ \
+ product(uintx, CMSIndexedFreeListReplenish, 4, \
+ "Replenish an indexed free list with this number of chunks") \
+ range(1, max_uintx) \
+ \
+ product(bool, CMSReplenishIntermediate, true, \
+ "Replenish all intermediate free-list caches") \
+ \
+ product(bool, CMSSplitIndexedFreeListBlocks, true, \
+ "When satisfying batched demand, split blocks from the " \
+ "IndexedFreeList whose size is a multiple of requested size") \
+ \
+ product(bool, CMSLoopWarn, false, \
+ "Warn in case of excessive CMS looping") \
+ \
+ notproduct(bool, CMSMarkStackOverflowALot, false, \
+ "Simulate frequent marking stack / work queue overflow") \
+ \
+ notproduct(uintx, CMSMarkStackOverflowInterval, 1000, \
+ "An \"interval\" counter that determines how frequently " \
+ "to simulate overflow; a smaller number increases frequency") \
+ \
+ product(uintx, CMSMaxAbortablePrecleanLoops, 0, \
+ "Maximum number of abortable preclean iterations, if > 0") \
+ range(0, max_uintx) \
+ \
+ product(intx, CMSMaxAbortablePrecleanTime, 5000, \
+ "Maximum time in abortable preclean (in milliseconds)") \
+ range(0, max_intx) \
+ \
+ product(uintx, CMSAbortablePrecleanMinWorkPerIteration, 100, \
+ "Nominal minimum work per abortable preclean iteration") \
+ range(0, max_uintx) \
+ \
+ manageable(intx, CMSAbortablePrecleanWaitMillis, 100, \
+ "Time that we sleep between iterations when not given " \
+ "enough work per iteration") \
+ range(0, max_intx) \
+ \
+ /* 4096 = CardTable::card_size_in_words * BitsPerWord */ \
+ product(size_t, CMSRescanMultiple, 32, \
+ "Size (in cards) of CMS parallel rescan task") \
+ range(1, SIZE_MAX / 4096) \
+ constraint(CMSRescanMultipleConstraintFunc,AfterMemoryInit) \
+ \
+ /* 4096 = CardTable::card_size_in_words * BitsPerWord */ \
+ product(size_t, CMSConcMarkMultiple, 32, \
+ "Size (in cards) of CMS concurrent MT marking task") \
+ range(1, SIZE_MAX / 4096) \
+ constraint(CMSConcMarkMultipleConstraintFunc,AfterMemoryInit) \
+ \
+ product(bool, CMSAbortSemantics, false, \
+ "Whether abort-on-overflow semantics is implemented") \
+ \
+ product(bool, CMSParallelInitialMarkEnabled, true, \
+ "Use the parallel initial mark.") \
+ \
+ product(bool, CMSParallelRemarkEnabled, true, \
+ "Whether parallel remark enabled (only if ParNewGC)") \
+ \
+ product(bool, CMSParallelSurvivorRemarkEnabled, true, \
+ "Whether parallel remark of survivor space " \
+ "enabled (effective only if CMSParallelRemarkEnabled)") \
+ \
+ product(bool, CMSPLABRecordAlways, true, \
+ "Always record survivor space PLAB boundaries (effective only " \
+ "if CMSParallelSurvivorRemarkEnabled)") \
+ \
+ product(bool, CMSEdenChunksRecordAlways, true, \
+ "Always record eden chunks used for the parallel initial mark " \
+ "or remark of eden") \
+ \
+ product(bool, CMSConcurrentMTEnabled, true, \
+ "Whether multi-threaded concurrent work enabled " \
+ "(effective only if ParNewGC)") \
+ \
+ product(bool, CMSPrecleaningEnabled, true, \
+ "Whether concurrent precleaning enabled") \
+ \
+ product(uintx, CMSPrecleanIter, 3, \
+ "Maximum number of precleaning iteration passes") \
+ range(0, 9) \
+ \
+ product(uintx, CMSPrecleanDenominator, 3, \
+ "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \
+ "ratio") \
+ range(1, max_uintx) \
+ constraint(CMSPrecleanDenominatorConstraintFunc,AfterErgo) \
+ \
+ product(uintx, CMSPrecleanNumerator, 2, \
+ "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \
+ "ratio") \
+ range(0, max_uintx-1) \
+ constraint(CMSPrecleanNumeratorConstraintFunc,AfterErgo) \
+ \
+ product(bool, CMSPrecleanRefLists1, true, \
+ "Preclean ref lists during (initial) preclean phase") \
+ \
+ product(bool, CMSPrecleanRefLists2, false, \
+ "Preclean ref lists during abortable preclean phase") \
+ \
+ product(bool, CMSPrecleanSurvivors1, false, \
+ "Preclean survivors during (initial) preclean phase") \
+ \
+ product(bool, CMSPrecleanSurvivors2, true, \
+ "Preclean survivors during abortable preclean phase") \
+ \
+ product(uintx, CMSPrecleanThreshold, 1000, \
+ "Do not iterate again if number of dirty cards is less than this")\
+ range(100, max_uintx) \
+ \
+ product(bool, CMSCleanOnEnter, true, \
+ "Clean-on-enter optimization for reducing number of dirty cards") \
+ \
+ product(uintx, CMSRemarkVerifyVariant, 1, \
+ "Choose variant (1,2) of verification following remark") \
+ range(1, 2) \
+ \
+ product(size_t, CMSScheduleRemarkEdenSizeThreshold, 2*M, \
+ "If Eden size is below this, do not try to schedule remark") \
+ range(0, max_uintx) \
+ \
+ product(uintx, CMSScheduleRemarkEdenPenetration, 50, \
+ "The Eden occupancy percentage (0-100) at which " \
+ "to try and schedule remark pause") \
+ range(0, 100) \
+ \
+ product(uintx, CMSScheduleRemarkSamplingRatio, 5, \
+ "Start sampling eden top at least before young gen " \
+ "occupancy reaches 1/<ratio> of the size at which " \
+ "we plan to schedule remark") \
+ range(1, max_uintx) \
+ \
+ product(uintx, CMSSamplingGrain, 16*K, \
+ "The minimum distance between eden samples for CMS (see above)") \
+ range(ObjectAlignmentInBytes, max_uintx) \
+ constraint(CMSSamplingGrainConstraintFunc,AfterMemoryInit) \
+ \
+ product(bool, CMSScavengeBeforeRemark, false, \
+ "Attempt scavenge before the CMS remark step") \
+ \
+ product(uintx, CMSWorkQueueDrainThreshold, 10, \
+ "Don't drain below this size per parallel worker/thief") \
+ range(1, max_juint) \
+ constraint(CMSWorkQueueDrainThresholdConstraintFunc,AfterErgo) \
+ \
+ manageable(intx, CMSWaitDuration, 2000, \
+ "Time in milliseconds that CMS thread waits for young GC") \
+ range(min_jint, max_jint) \
+ \
+ develop(uintx, CMSCheckInterval, 1000, \
+ "Interval in milliseconds that CMS thread checks if it " \
+ "should start a collection cycle") \
+ \
+ product(bool, CMSYield, true, \
+ "Yield between steps of CMS") \
+ \
+ product(size_t, CMSBitMapYieldQuantum, 10*M, \
+ "Bitmap operations should process at most this many bits " \
+ "between yields") \
+ range(1, max_uintx) \
+ constraint(CMSBitMapYieldQuantumConstraintFunc,AfterMemoryInit) \
+ \
+ product(bool, CMSPrintChunksInDump, false, \
+ "If logging for the \"gc\" and \"promotion\" tags is enabled on" \
+ "trace level include more detailed information about the" \
+ "free chunks") \
+ \
+ product(bool, CMSPrintObjectsInDump, false, \
+ "If logging for the \"gc\" and \"promotion\" tags is enabled on" \
+ "trace level include more detailed information about the" \
+ "allocated objects") \
+ \
+ diagnostic(bool, FLSVerifyAllHeapReferences, false, \
+ "Verify that all references across the FLS boundary " \
+ "are to valid objects") \
+ \
+ diagnostic(bool, FLSVerifyLists, false, \
+ "Do lots of (expensive) FreeListSpace verification") \
+ \
+ diagnostic(bool, FLSVerifyIndexTable, false, \
+ "Do lots of (expensive) FLS index table verification") \
+ \
+ product(uintx, CMSTriggerRatio, 80, \
+ "Percentage of MinHeapFreeRatio in CMS generation that is " \
+ "allocated before a CMS collection cycle commences") \
+ range(0, 100) \
+ \
+ product(uintx, CMSBootstrapOccupancy, 50, \
+ "Percentage CMS generation occupancy at which to " \
+ "initiate CMS collection for bootstrapping collection stats") \
+ range(0, 100) \
+ \
+ product(intx, CMSInitiatingOccupancyFraction, -1, \
+ "Percentage CMS generation occupancy to start a CMS collection " \
+ "cycle. A negative value means that CMSTriggerRatio is used") \
+ range(min_intx, 100) \
+ \
+ manageable(intx, CMSTriggerInterval, -1, \
+ "Commence a CMS collection cycle (at least) every so many " \
+ "milliseconds (0 permanently, -1 disabled)") \
+ range(-1, max_intx) \
+ \
+ product(bool, UseCMSInitiatingOccupancyOnly, false, \
+ "Only use occupancy as a criterion for starting a CMS collection")\
+ \
+ product(uintx, CMSIsTooFullPercentage, 98, \
+ "An absolute ceiling above which CMS will always consider the " \
+ "unloading of classes when class unloading is enabled") \
+ range(0, 100) \
+ \
+ develop(bool, CMSTestInFreeList, false, \
+ "Check if the coalesced range is already in the " \
+ "free lists as claimed") \
+ \
+ notproduct(bool, CMSVerifyReturnedBytes, false, \
+ "Check that all the garbage collected was returned to the " \
+ "free lists") \
+ \
+ diagnostic(bool, BindCMSThreadToCPU, false, \
+ "Bind CMS Thread to CPU if possible") \
+ \
+ diagnostic(uintx, CPUForCMSThread, 0, \
+ "When BindCMSThreadToCPU is true, the CPU to bind CMS thread to") \
+ range(0, max_juint) \
+ \
+ product(uintx, CMSCoordinatorYieldSleepCount, 10, \
+ "Number of times the coordinator GC thread will sleep while " \
+ "yielding before giving up and resuming GC") \
+ range(0, max_juint) \
+ \
+ product(uintx, CMSYieldSleepCount, 0, \
+ "Number of times a GC thread (minus the coordinator) " \
+ "will sleep while yielding before giving up and resuming GC") \
+ range(0, max_juint) \
+ \
+ product(bool, ParGCUseLocalOverflow, false, \
+ "Instead of a global overflow list, use local overflow stacks") \
+ \
+ product(bool, ParGCTrimOverflow, true, \
+ "Eagerly trim the local overflow lists " \
+ "(when ParGCUseLocalOverflow)") \
+ \
+ notproduct(bool, ParGCWorkQueueOverflowALot, false, \
+ "Simulate work queue overflow in ParNew") \
+ \
+ notproduct(uintx, ParGCWorkQueueOverflowInterval, 1000, \
+ "An `interval' counter that determines how frequently " \
+ "we simulate overflow; a smaller number increases frequency") \
+ \
+ product(uintx, ParGCDesiredObjsFromOverflowList, 20, \
+ "The desired number of objects to claim from the overflow list") \
+ range(0, max_uintx) \
+ \
+ diagnostic(uintx, ParGCStridesPerThread, 2, \
+ "The number of strides per worker thread that we divide up the " \
+ "card table scanning work into") \
+ range(1, max_uintx) \
+ constraint(ParGCStridesPerThreadConstraintFunc,AfterErgo) \
+ \
+ diagnostic(intx, ParGCCardsPerStrideChunk, 256, \
+ "The number of cards in each chunk of the parallel chunks used " \
+ "during card table scanning") \
+ range(1, max_intx) \
+ constraint(ParGCCardsPerStrideChunkConstraintFunc,AfterMemoryInit)
+
+#endif // SHARE_GC_CMS_CMS_GLOBALS_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/cms/cms_specialized_oop_closures.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_CMS_CMS_SPECIALIZED_OOP_CLOSURES_HPP
+#define SHARE_GC_CMS_CMS_SPECIALIZED_OOP_CLOSURES_HPP
+
+// The following OopClosure types get specialized versions of
+// "oop_oop_iterate" that invoke the closures' do_oop methods
+// non-virtually, using a mechanism defined in this file. Extend these
+// macros in the obvious way to add specializations for new closures.
+
+// Forward declarations.
+
+// ParNew
+class ParScanWithBarrierClosure;
+class ParScanWithoutBarrierClosure;
+
+// CMS
+class MarkRefsIntoAndScanClosure;
+class ParMarkRefsIntoAndScanClosure;
+class PushAndMarkClosure;
+class ParPushAndMarkClosure;
+class PushOrMarkClosure;
+class ParPushOrMarkClosure;
+class CMSKeepAliveClosure;
+class CMSInnerParMarkAndPushClosure;
+
+#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f) \
+ f(ParScanWithBarrierClosure,_nv) \
+ f(ParScanWithoutBarrierClosure,_nv)
+
+#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_CMS(f) \
+ f(MarkRefsIntoAndScanClosure,_nv) \
+ f(ParMarkRefsIntoAndScanClosure,_nv) \
+ f(PushAndMarkClosure,_nv) \
+ f(ParPushAndMarkClosure,_nv) \
+ f(PushOrMarkClosure,_nv) \
+ f(ParPushOrMarkClosure,_nv) \
+ f(CMSKeepAliveClosure,_nv) \
+ f(CMSInnerParMarkAndPushClosure,_nv)
+
+#define SPECIALIZED_PAR_OOP_ITERATE_CLOSURES(f) \
+ f(MarkRefsIntoAndScanClosure,_nv) \
+ f(PushAndMarkClosure,_nv) \
+ f(ParMarkRefsIntoAndScanClosure,_nv) \
+ f(ParPushAndMarkClosure,_nv)
+
+#define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f) \
+ f(ParScanWithBarrierClosure,_nv) \
+ f(ParScanWithoutBarrierClosure,_nv)
+
+#endif // SHARE_GC_CMS_CMS_SPECIALIZED_OOP_CLOSURES_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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/cms/commandLineFlagConstraintsCMS.hpp"
+#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
+#include "gc/shared/cardTableRS.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/genCollectedHeap.hpp"
+#include "gc/shared/commandLineFlagConstraintsGC.hpp"
+#include "memory/universe.hpp"
+#include "runtime/commandLineFlagRangeList.hpp"
+#include "runtime/globals_extension.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+static Flag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) {
+ // CMSWorkQueueDrainThreshold is verified to be less than max_juint
+ if (UseConcMarkSweepGC && (threads > (uint)(max_jint / (uint)threshold))) {
+ CommandLineError::print(verbose,
+ "ParallelGCThreads (" UINT32_FORMAT ") or CMSWorkQueueDrainThreshold ("
+ UINTX_FORMAT ") is too large\n",
+ threads, threshold);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose) {
+ // To avoid overflow at ParScanClosure::do_oop_work.
+ if (UseConcMarkSweepGC && (value > (max_jint / 10))) {
+ CommandLineError::print(verbose,
+ "ParallelGCThreads (" UINT32_FORMAT ") must be "
+ "less than or equal to " UINT32_FORMAT " for CMS GC\n",
+ value, (max_jint / 10));
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(value, CMSWorkQueueDrainThreshold, verbose);
+}
+Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) {
+ if (UseConcMarkSweepGC && (value > ((uintx)max_jint / (uintx)ParallelGCThreads))) {
+ CommandLineError::print(verbose,
+ "ParGCStridesPerThread (" UINTX_FORMAT ") must be "
+ "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n",
+ value, ((uintx)max_jint / (uintx)ParallelGCThreads));
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) {
+ if (UseConcMarkSweepGC) {
+ // ParGCCardsPerStrideChunk should be compared with card table size.
+ size_t heap_size = Universe::heap()->reserved_region().word_size();
+ CardTableRS* ct = GenCollectedHeap::heap()->rem_set();
+ size_t card_table_size = ct->cards_required(heap_size) - 1; // Valid card table size
+
+ if ((size_t)value > card_table_size) {
+ CommandLineError::print(verbose,
+ "ParGCCardsPerStrideChunk (" INTX_FORMAT ") is too large for the heap size and "
+ "must be less than or equal to card table size (" SIZE_FORMAT ")\n",
+ value, card_table_size);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+
+ // ParGCCardsPerStrideChunk is used with n_strides(ParallelGCThreads*ParGCStridesPerThread)
+ // from CardTableRS::process_stride(). Note that ParGCStridesPerThread is already checked
+ // not to make an overflow with ParallelGCThreads from its constraint function.
+ uintx n_strides = ParallelGCThreads * ParGCStridesPerThread;
+ uintx ergo_max = max_uintx / n_strides;
+ if ((uintx)value > ergo_max) {
+ CommandLineError::print(verbose,
+ "ParGCCardsPerStrideChunk (" INTX_FORMAT ") must be "
+ "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n",
+ value, ergo_max);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) {
+ Flag::Error status = Flag::SUCCESS;
+
+ if (UseConcMarkSweepGC) {
+ if (value > CMSOldPLABMax) {
+ CommandLineError::print(verbose,
+ "CMSOldPLABMin (" SIZE_FORMAT ") must be "
+ "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n",
+ value, CMSOldPLABMax);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ status = MaxPLABSizeBounds("CMSOldPLABMin", value, verbose);
+ }
+ return status;
+}
+
+Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) {
+ Flag::Error status = Flag::SUCCESS;
+
+ if (UseConcMarkSweepGC) {
+ status = MaxPLABSizeBounds("CMSOldPLABMax", value, verbose);
+ }
+ return status;
+}
+
+static Flag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, bool verbose) {
+ if (UseConcMarkSweepGC) {
+ ConcurrentMarkSweepGeneration* cms = (ConcurrentMarkSweepGeneration*)GenCollectedHeap::heap()->old_gen();
+ const size_t ergo_max = cms->cmsSpace()->max_flag_size_for_task_size();
+ if (value > ergo_max) {
+ CommandLineError::print(verbose,
+ "%s (" SIZE_FORMAT ") must be "
+ "less than or equal to ergonomic maximum (" SIZE_FORMAT ") "
+ "which is based on the maximum size of the old generation of the Java heap\n",
+ name, value, ergo_max);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+
+ return Flag::SUCCESS;
+}
+
+Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) {
+ Flag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose);
+
+ if (status == Flag::SUCCESS && UseConcMarkSweepGC) {
+ // CMSParRemarkTask::do_dirty_card_rescan_tasks requires CompactibleFreeListSpace::rescan_task_size()
+ // to be aligned to CardTable::card_size * BitsPerWord.
+ // Note that rescan_task_size() will be aligned if CMSRescanMultiple is a multiple of 'HeapWordSize'
+ // because rescan_task_size() is CardTable::card_size / HeapWordSize * BitsPerWord.
+ if (value % HeapWordSize != 0) {
+ CommandLineError::print(verbose,
+ "CMSRescanMultiple (" SIZE_FORMAT ") must be "
+ "a multiple of " SIZE_FORMAT "\n",
+ value, HeapWordSize);
+ status = Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+
+ return status;
+}
+
+Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) {
+ return CMSReservedAreaConstraintFunc("CMSConcMarkMultiple", value, verbose);
+}
+
+Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) {
+ if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) {
+ CommandLineError::print(verbose,
+ "CMSPrecleanDenominator (" UINTX_FORMAT ") must be "
+ "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n",
+ value, CMSPrecleanNumerator);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) {
+ if (UseConcMarkSweepGC && (value >= CMSPrecleanDenominator)) {
+ CommandLineError::print(verbose,
+ "CMSPrecleanNumerator (" UINTX_FORMAT ") must be "
+ "less than CMSPrecleanDenominator (" UINTX_FORMAT ")\n",
+ value, CMSPrecleanDenominator);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) {
+ if (UseConcMarkSweepGC) {
+ size_t max_capacity = GenCollectedHeap::heap()->young_gen()->max_capacity();
+ if (value > max_uintx - max_capacity) {
+ CommandLineError::print(verbose,
+ "CMSSamplingGrain (" UINTX_FORMAT ") must be "
+ "less than or equal to ergonomic maximum (" SIZE_FORMAT ")\n",
+ value, max_uintx - max_capacity);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) {
+ if (UseConcMarkSweepGC) {
+ return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(ParallelGCThreads, value, verbose);
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) {
+ // Skip for current default value.
+ if (UseConcMarkSweepGC && FLAG_IS_CMDLINE(CMSBitMapYieldQuantum)) {
+ // CMSBitMapYieldQuantum should be compared with mark bitmap size.
+ ConcurrentMarkSweepGeneration* cms = (ConcurrentMarkSweepGeneration*)GenCollectedHeap::heap()->old_gen();
+ size_t bitmap_size = cms->collector()->markBitMap()->sizeInWords();
+
+ if (value > bitmap_size) {
+ CommandLineError::print(verbose,
+ "CMSBitMapYieldQuantum (" SIZE_FORMAT ") must "
+ "be less than or equal to bitmap size (" SIZE_FORMAT ") "
+ "whose size corresponds to the size of old generation of the Java heap\n",
+ value, bitmap_size);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose) {
+ if (value == 0) {
+ CommandLineError::print(verbose,
+ "OldPLABSize (" SIZE_FORMAT ") must be greater than 0",
+ value);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ // For CMS, OldPLABSize is the number of free blocks of a given size that are used when
+ // replenishing the local per-worker free list caches.
+ // For more details, please refer to Arguments::set_cms_and_parnew_gc_flags().
+ return MaxPLABSizeBounds("OldPLABSize", value, verbose);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/cms/commandLineFlagConstraintsCMS.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_CMS_COMMANDLINEFLAGCONSTRAINTSCMS_HPP
+#define SHARE_GC_CMS_COMMANDLINEFLAGCONSTRAINTSCMS_HPP
+
+#include "runtime/globals.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+// CMS Flag Constraints
+Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose);
+Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose);
+Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose);
+Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose);
+Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose);
+Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose);
+Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose);
+Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose);
+Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose);
+Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose);
+Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose);
+
+// CMS Subconstraints
+Flag::Error ParallelGCThreadsConstraintFuncCMS(uint value, bool verbose);
+Flag::Error OldPLABSizeConstraintFuncCMS(size_t value, bool verbose);
+
+#endif // SHARE_GC_CMS_COMMANDLINEFLAGCONSTRAINTSCMS_HPP
--- a/src/hotspot/share/gc/cms/compactibleFreeListSpace.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/compactibleFreeListSpace.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -35,6 +35,7 @@
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
+#include "memory/binaryTreeDictionary.inline.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/access.inline.hpp"
@@ -49,6 +50,244 @@
#include "utilities/align.hpp"
#include "utilities/copy.hpp"
+// Specialize for AdaptiveFreeList which tries to avoid
+// splitting a chunk of a size that is under populated in favor of
+// an over populated size. The general get_better_list() just returns
+// the current list.
+template <>
+TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >*
+TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >::get_better_list(
+ BinaryTreeDictionary<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* dictionary) {
+ // A candidate chunk has been found. If it is already under
+ // populated, get a chunk associated with the hint for this
+ // chunk.
+
+ TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* curTL = this;
+ if (curTL->surplus() <= 0) {
+ /* Use the hint to find a size with a surplus, and reset the hint. */
+ TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
+ while (hintTL->hint() != 0) {
+ assert(hintTL->hint() > hintTL->size(),
+ "hint points in the wrong direction");
+ hintTL = dictionary->find_list(hintTL->hint());
+ assert(curTL != hintTL, "Infinite loop");
+ if (hintTL == NULL ||
+ hintTL == curTL /* Should not happen but protect against it */ ) {
+ // No useful hint. Set the hint to NULL and go on.
+ curTL->set_hint(0);
+ break;
+ }
+ assert(hintTL->size() > curTL->size(), "hint is inconsistent");
+ if (hintTL->surplus() > 0) {
+ // The hint led to a list that has a surplus. Use it.
+ // Set the hint for the candidate to an overpopulated
+ // size.
+ curTL->set_hint(hintTL->size());
+ // Change the candidate.
+ curTL = hintTL;
+ break;
+ }
+ }
+ }
+ return curTL;
+}
+
+void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth) {
+ TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* nd = find_list(size);
+ if (nd) {
+ if (split) {
+ if (birth) {
+ nd->increment_split_births();
+ nd->increment_surplus();
+ } else {
+ nd->increment_split_deaths();
+ nd->decrement_surplus();
+ }
+ } else {
+ if (birth) {
+ nd->increment_coal_births();
+ nd->increment_surplus();
+ } else {
+ nd->increment_coal_deaths();
+ nd->decrement_surplus();
+ }
+ }
+ }
+ // A list for this size may not be found (nd == 0) if
+ // This is a death where the appropriate list is now
+ // empty and has been removed from the list.
+ // This is a birth associated with a LinAB. The chunk
+ // for the LinAB is not in the dictionary.
+}
+
+bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) {
+ if (FLSAlwaysCoalesceLarge) return true;
+
+ TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* list_of_size = find_list(size);
+ // None of requested size implies overpopulated.
+ return list_of_size == NULL || list_of_size->coal_desired() <= 0 ||
+ list_of_size->count() > list_of_size->coal_desired();
+}
+
+// For each list in the tree, calculate the desired, desired
+// coalesce, count before sweep, and surplus before sweep.
+class BeginSweepClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ double _percentage;
+ float _inter_sweep_current;
+ float _inter_sweep_estimate;
+ float _intra_sweep_estimate;
+
+ public:
+ BeginSweepClosure(double p, float inter_sweep_current,
+ float inter_sweep_estimate,
+ float intra_sweep_estimate) :
+ _percentage(p),
+ _inter_sweep_current(inter_sweep_current),
+ _inter_sweep_estimate(inter_sweep_estimate),
+ _intra_sweep_estimate(intra_sweep_estimate) { }
+
+ void do_list(AdaptiveFreeList<FreeChunk>* fl) {
+ double coalSurplusPercent = _percentage;
+ fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate);
+ fl->set_coal_desired((ssize_t)((double)fl->desired() * coalSurplusPercent));
+ fl->set_before_sweep(fl->count());
+ fl->set_bfr_surp(fl->surplus());
+ }
+};
+
+void AFLBinaryTreeDictionary::begin_sweep_dict_census(double coalSurplusPercent,
+ float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
+ BeginSweepClosure bsc(coalSurplusPercent, inter_sweep_current,
+ inter_sweep_estimate,
+ intra_sweep_estimate);
+ bsc.do_tree(root());
+}
+
+// Calculate surpluses for the lists in the tree.
+class setTreeSurplusClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ double percentage;
+ public:
+ setTreeSurplusClosure(double v) { percentage = v; }
+
+ void do_list(AdaptiveFreeList<FreeChunk>* fl) {
+ double splitSurplusPercent = percentage;
+ fl->set_surplus(fl->count() -
+ (ssize_t)((double)fl->desired() * splitSurplusPercent));
+ }
+};
+
+void AFLBinaryTreeDictionary::set_tree_surplus(double splitSurplusPercent) {
+ setTreeSurplusClosure sts(splitSurplusPercent);
+ sts.do_tree(root());
+}
+
+// Set hints for the lists in the tree.
+class setTreeHintsClosure : public DescendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ size_t hint;
+ public:
+ setTreeHintsClosure(size_t v) { hint = v; }
+
+ void do_list(AdaptiveFreeList<FreeChunk>* fl) {
+ fl->set_hint(hint);
+ assert(fl->hint() == 0 || fl->hint() > fl->size(),
+ "Current hint is inconsistent");
+ if (fl->surplus() > 0) {
+ hint = fl->size();
+ }
+ }
+};
+
+void AFLBinaryTreeDictionary::set_tree_hints(void) {
+ setTreeHintsClosure sth(0);
+ sth.do_tree(root());
+}
+
+// Save count before previous sweep and splits and coalesces.
+class clearTreeCensusClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ void do_list(AdaptiveFreeList<FreeChunk>* fl) {
+ fl->set_prev_sweep(fl->count());
+ fl->set_coal_births(0);
+ fl->set_coal_deaths(0);
+ fl->set_split_births(0);
+ fl->set_split_deaths(0);
+ }
+};
+
+void AFLBinaryTreeDictionary::clear_tree_census(void) {
+ clearTreeCensusClosure ctc;
+ ctc.do_tree(root());
+}
+
+// Do reporting and post sweep clean up.
+void AFLBinaryTreeDictionary::end_sweep_dict_census(double splitSurplusPercent) {
+ // Does walking the tree 3 times hurt?
+ set_tree_surplus(splitSurplusPercent);
+ set_tree_hints();
+ LogTarget(Trace, gc, freelist, stats) log;
+ if (log.is_enabled()) {
+ LogStream out(log);
+ report_statistics(&out);
+ }
+ clear_tree_census();
+}
+
+// Print census information - counts, births, deaths, etc.
+// for each list in the tree. Also print some summary
+// information.
+class PrintTreeCensusClosure : public AscendTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ int _print_line;
+ size_t _total_free;
+ AdaptiveFreeList<FreeChunk> _total;
+
+ public:
+ PrintTreeCensusClosure() {
+ _print_line = 0;
+ _total_free = 0;
+ }
+ AdaptiveFreeList<FreeChunk>* total() { return &_total; }
+ size_t total_free() { return _total_free; }
+
+ void do_list(AdaptiveFreeList<FreeChunk>* fl) {
+ LogStreamHandle(Debug, gc, freelist, census) out;
+
+ if (++_print_line >= 40) {
+ AdaptiveFreeList<FreeChunk>::print_labels_on(&out, "size");
+ _print_line = 0;
+ }
+ fl->print_on(&out);
+ _total_free += fl->count() * fl->size() ;
+ total()->set_count( total()->count() + fl->count() );
+ total()->set_bfr_surp( total()->bfr_surp() + fl->bfr_surp() );
+ total()->set_surplus( total()->split_deaths() + fl->surplus() );
+ total()->set_desired( total()->desired() + fl->desired() );
+ total()->set_prev_sweep( total()->prev_sweep() + fl->prev_sweep() );
+ total()->set_before_sweep(total()->before_sweep() + fl->before_sweep());
+ total()->set_coal_births( total()->coal_births() + fl->coal_births() );
+ total()->set_coal_deaths( total()->coal_deaths() + fl->coal_deaths() );
+ total()->set_split_births(total()->split_births() + fl->split_births());
+ total()->set_split_deaths(total()->split_deaths() + fl->split_deaths());
+ }
+};
+
+void AFLBinaryTreeDictionary::print_dict_census(outputStream* st) const {
+
+ st->print_cr("BinaryTree");
+ AdaptiveFreeList<FreeChunk>::print_labels_on(st, "size");
+ PrintTreeCensusClosure ptc;
+ ptc.do_tree(root());
+
+ AdaptiveFreeList<FreeChunk>* total = ptc.total();
+ AdaptiveFreeList<FreeChunk>::print_labels_on(st, " ");
+ total->print_on(st, "TOTAL\t");
+ st->print_cr("total_free(words): " SIZE_FORMAT_W(16) " growth: %8.5f deficit: %8.5f",
+ ptc.total_free(),
+ (double)(total->split_births() + total->coal_births()
+ - total->split_deaths() - total->coal_deaths())
+ /(total->prev_sweep() != 0 ? (double)total->prev_sweep() : 1.0),
+ (double)(total->desired() - total->count())
+ /(total->desired() != 0 ? (double)total->desired() : 1.0));
+}
+
/////////////////////////////////////////////////////////////////////////
//// CompactibleFreeListSpace
/////////////////////////////////////////////////////////////////////////
@@ -181,7 +420,7 @@
} else {
// if the object isn't moving we can just set the mark to the default
// mark and handle it specially later on.
- q->init_mark();
+ q->init_mark_raw();
assert(q->forwardee() == NULL, "should be forwarded to NULL");
}
--- a/src/hotspot/share/gc/cms/compactibleFreeListSpace.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/compactibleFreeListSpace.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -48,6 +48,37 @@
class ObjectClosureCareful;
class Klass;
+class AFLBinaryTreeDictionary : public BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> > {
+ public:
+ AFLBinaryTreeDictionary(MemRegion mr)
+ : BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> >(mr) {}
+
+ // Find the list with size "size" in the binary tree and update
+ // the statistics in the list according to "split" (chunk was
+ // split or coalesce) and "birth" (chunk was added or removed).
+ void dict_census_update(size_t size, bool split, bool birth);
+ // Return true if the dictionary is overpopulated (more chunks of
+ // this size than desired) for size "size".
+ bool coal_dict_over_populated(size_t size);
+ // Methods called at the beginning of a sweep to prepare the
+ // statistics for the sweep.
+ void begin_sweep_dict_census(double coalSurplusPercent,
+ float inter_sweep_current,
+ float inter_sweep_estimate,
+ float intra_sweep_estimate);
+ // Methods called after the end of a sweep to modify the
+ // statistics for the sweep.
+ void end_sweep_dict_census(double splitSurplusPercent);
+ // Accessors for statistics
+ void set_tree_surplus(double splitSurplusPercent);
+ void set_tree_hints(void);
+ // Reset statistics for all the lists in the tree.
+ void clear_tree_census(void);
+ // Print the statistics for all the lists in the tree. Also may
+ // print out summaries.
+ void print_dict_census(outputStream* st) const;
+};
+
class LinearAllocBlock {
public:
LinearAllocBlock() : _ptr(0), _word_size(0), _refillSize(0),
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -29,6 +29,7 @@
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/cms/cmsCollectorPolicy.hpp"
+#include "gc/cms/cmsGCStats.hpp"
#include "gc/cms/cmsHeap.hpp"
#include "gc/cms/cmsOopClosures.inline.hpp"
#include "gc/cms/compactibleFreeListSpace.hpp"
@@ -59,6 +60,7 @@
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.hpp"
+#include "memory/binaryTreeDictionary.inline.hpp"
#include "memory/iterator.inline.hpp"
#include "memory/padded.hpp"
#include "memory/resourceArea.hpp"
@@ -1042,7 +1044,7 @@
// Except with compressed oops it's the mark word.
HeapWord* old_ptr = (HeapWord*)old;
// Restore the mark word copied above.
- obj->set_mark(m);
+ obj->set_mark_raw(m);
assert(obj->klass_or_null() == NULL, "Object should be uninitialized here.");
assert(!((FreeChunk*)obj_ptr)->is_free(), "Error, block will look free but show wrong size");
OrderAccess::storestore();
@@ -7814,8 +7816,8 @@
const markOop proto = markOopDesc::prototype();
NOT_PRODUCT(ssize_t n = 0;)
for (oop next; i > 0 && cur != NULL; cur = next, i--) {
- next = oop(cur->mark());
- cur->set_mark(proto); // until proven otherwise
+ next = oop(cur->mark_raw());
+ cur->set_mark_raw(proto); // until proven otherwise
assert(oopDesc::is_oop(cur), "Should be an oop");
bool res = stack->push(cur);
assert(res, "Bit off more than can chew?");
@@ -7898,8 +7900,8 @@
size_t i = num;
oop cur = prefix;
// Walk down the first "num" objects, unless we reach the end.
- for (; i > 1 && cur->mark() != NULL; cur = oop(cur->mark()), i--);
- if (cur->mark() == NULL) {
+ for (; i > 1 && cur->mark_raw() != NULL; cur = oop(cur->mark_raw()), i--);
+ if (cur->mark_raw() == NULL) {
// We have "num" or fewer elements in the list, so there
// is nothing to return to the global list.
// Write back the NULL in lieu of the BUSY we wrote
@@ -7909,9 +7911,9 @@
}
} else {
// Chop off the suffix and return it to the global list.
- assert(cur->mark() != BUSY, "Error");
- oop suffix_head = cur->mark(); // suffix will be put back on global list
- cur->set_mark(NULL); // break off suffix
+ assert(cur->mark_raw() != BUSY, "Error");
+ oop suffix_head = cur->mark_raw(); // suffix will be put back on global list
+ cur->set_mark_raw(NULL); // break off suffix
// It's possible that the list is still in the empty(busy) state
// we left it in a short while ago; in that case we may be
// able to place back the suffix without incurring the cost
@@ -7931,18 +7933,18 @@
// Too bad, someone else sneaked in (at least) an element; we'll need
// to do a splice. Find tail of suffix so we can prepend suffix to global
// list.
- for (cur = suffix_head; cur->mark() != NULL; cur = (oop)(cur->mark()));
+ for (cur = suffix_head; cur->mark_raw() != NULL; cur = (oop)(cur->mark_raw()));
oop suffix_tail = cur;
- assert(suffix_tail != NULL && suffix_tail->mark() == NULL,
+ assert(suffix_tail != NULL && suffix_tail->mark_raw() == NULL,
"Tautology");
observed_overflow_list = _overflow_list;
do {
cur_overflow_list = observed_overflow_list;
if (cur_overflow_list != BUSY) {
// Do the splice ...
- suffix_tail->set_mark(markOop(cur_overflow_list));
+ suffix_tail->set_mark_raw(markOop(cur_overflow_list));
} else { // cur_overflow_list == BUSY
- suffix_tail->set_mark(NULL);
+ suffix_tail->set_mark_raw(NULL);
}
// ... and try to place spliced list back on overflow_list ...
observed_overflow_list =
@@ -7958,8 +7960,8 @@
oop next;
NOT_PRODUCT(ssize_t n = 0;)
for (cur = prefix; cur != NULL; cur = next) {
- next = oop(cur->mark());
- cur->set_mark(proto); // until proven otherwise
+ next = oop(cur->mark_raw());
+ cur->set_mark_raw(proto); // until proven otherwise
assert(oopDesc::is_oop(cur), "Should be an oop");
bool res = work_q->push(cur);
assert(res, "Bit off more than we can chew?");
@@ -7977,7 +7979,7 @@
NOT_PRODUCT(_num_par_pushes++;)
assert(oopDesc::is_oop(p), "Not an oop");
preserve_mark_if_necessary(p);
- p->set_mark((markOop)_overflow_list);
+ p->set_mark_raw((markOop)_overflow_list);
_overflow_list = p;
}
@@ -7991,9 +7993,9 @@
do {
cur_overflow_list = observed_overflow_list;
if (cur_overflow_list != BUSY) {
- p->set_mark(markOop(cur_overflow_list));
+ p->set_mark_raw(markOop(cur_overflow_list));
} else {
- p->set_mark(NULL);
+ p->set_mark_raw(NULL);
}
observed_overflow_list =
Atomic::cmpxchg((oopDesc*)p, &_overflow_list, (oopDesc*)cur_overflow_list);
@@ -8018,21 +8020,21 @@
void CMSCollector::preserve_mark_work(oop p, markOop m) {
_preserved_oop_stack.push(p);
_preserved_mark_stack.push(m);
- assert(m == p->mark(), "Mark word changed");
+ assert(m == p->mark_raw(), "Mark word changed");
assert(_preserved_oop_stack.size() == _preserved_mark_stack.size(),
"bijection");
}
// Single threaded
void CMSCollector::preserve_mark_if_necessary(oop p) {
- markOop m = p->mark();
+ markOop m = p->mark_raw();
if (m->must_be_preserved(p)) {
preserve_mark_work(p, m);
}
}
void CMSCollector::par_preserve_mark_if_necessary(oop p) {
- markOop m = p->mark();
+ markOop m = p->mark_raw();
if (m->must_be_preserved(p)) {
MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
// Even though we read the mark word without holding
@@ -8040,7 +8042,7 @@
// because we "own" this oop, so no other thread can
// be trying to push it on the overflow list; see
// the assertion in preserve_mark_work() that checks
- // that m == p->mark().
+ // that m == p->mark_raw().
preserve_mark_work(p, m);
}
}
@@ -8073,10 +8075,10 @@
oop p = _preserved_oop_stack.pop();
assert(oopDesc::is_oop(p), "Should be an oop");
assert(_span.contains(p), "oop should be in _span");
- assert(p->mark() == markOopDesc::prototype(),
+ assert(p->mark_raw() == markOopDesc::prototype(),
"Set when taken from overflow list");
markOop m = _preserved_mark_stack.pop();
- p->set_mark(m);
+ p->set_mark_raw(m);
}
assert(_preserved_mark_stack.is_empty() && _preserved_oop_stack.is_empty(),
"stacks were cleared above");
--- a/src/hotspot/share/gc/cms/parNewGeneration.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/parNewGeneration.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1133,7 +1133,7 @@
// a forwarding pointer by a parallel thread. So we must save the mark
// word in a local and then analyze it.
oopDesc dummyOld;
- dummyOld.set_mark(m);
+ dummyOld.set_mark_raw(m);
assert(!dummyOld.is_forwarded(),
"should not be called with forwarding pointer mark word.");
@@ -1181,7 +1181,7 @@
assert(CMSHeap::heap()->is_in_reserved(new_obj), "illegal forwarding pointer value.");
forward_ptr = old->forward_to_atomic(new_obj);
// Restore the mark word copied above.
- new_obj->set_mark(m);
+ new_obj->set_mark_raw(m);
// Increment age if obj still in new generation
new_obj->incr_age();
par_scan_state->age_table()->add(new_obj, sz);
--- a/src/hotspot/share/gc/cms/parOopClosures.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/parOopClosures.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "gc/cms/parOopClosures.inline.hpp"
-#include "gc/shared/specialized_oop_closures.hpp"
+#include "gc/cms/cms_specialized_oop_closures.hpp"
#include "memory/iterator.inline.hpp"
// Generate ParNew specialized oop_oop_iterate functions.
--- a/src/hotspot/share/gc/cms/parOopClosures.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/parOopClosures.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,7 @@
#include "logging/logStream.hpp"
#include "oops/access.inline.hpp"
#include "oops/compressedOops.inline.hpp"
+#include "oops/oop.inline.hpp"
template <class T> inline void ParScanWeakRefClosure::do_oop_work(T* p) {
oop obj = RawAccess<OOP_NOT_NULL>::oop_load(p);
@@ -43,7 +44,7 @@
// we need to ensure that it is copied (see comment in
// ParScanClosure::do_oop_work).
Klass* objK = obj->klass();
- markOop m = obj->mark();
+ markOop m = obj->mark_raw();
oop new_obj;
if (m->is_marked()) { // Contains forwarding pointer.
new_obj = ParNewGeneration::real_forwardee(obj);
@@ -107,7 +108,7 @@
// overwritten with an overflow next pointer after the object is
// forwarded.
Klass* objK = obj->klass();
- markOop m = obj->mark();
+ markOop m = obj->mark_raw();
oop new_obj;
if (m->is_marked()) { // Contains forwarding pointer.
new_obj = ParNewGeneration::real_forwardee(obj);
--- a/src/hotspot/share/gc/cms/promotionInfo.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/promotionInfo.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,10 +85,10 @@
} \
if (curObj->hasDisplacedMark()) { \
/* restore displaced header */ \
- oop(curObj)->set_mark(nextDisplacedHeader()); \
+ oop(curObj)->set_mark_raw(nextDisplacedHeader()); \
} else { \
/* restore prototypical header */ \
- oop(curObj)->init_mark(); \
+ oop(curObj)->init_mark_raw(); \
} \
/* The "promoted_mark" should now not be set */ \
assert(!curObj->hasPromotedMark(), \
@@ -147,7 +147,7 @@
void PromotionInfo::track(PromotedObject* trackOop, Klass* klassOfOop) {
// make a copy of header as it may need to be spooled
- markOop mark = oop(trackOop)->mark();
+ markOop mark = oop(trackOop)->mark_raw();
trackOop->clear_next();
if (mark->must_be_preserved_for_cms_scavenge(klassOfOop)) {
// save non-prototypical header, and mark oop
@@ -287,7 +287,7 @@
// 2. each promoted object lies in this space
debug_only(
PromotedObject* junk = NULL;
- assert(junk->next_addr() == (void*)(oop(junk)->mark_addr()),
+ assert(junk->next_addr() == (void*)(oop(junk)->mark_addr_raw()),
"Offset of PromotedObject::_next is expected to align with "
" the OopDesc::_mark within OopDesc");
)
--- a/src/hotspot/share/gc/cms/vmStructs_cms.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/cms/vmStructs_cms.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,9 +25,15 @@
#ifndef SHARE_VM_GC_CMS_VMSTRUCTS_CMS_HPP
#define SHARE_VM_GC_CMS_VMSTRUCTS_CMS_HPP
-#define VM_STRUCTS_CMS(nonstatic_field, \
- volatile_nonstatic_field, \
- static_field) \
+#include "gc/cms/cmsHeap.hpp"
+#include "gc/cms/compactibleFreeListSpace.hpp"
+#include "gc/cms/concurrentMarkSweepGeneration.hpp"
+#include "gc/cms/concurrentMarkSweepThread.hpp"
+#include "gc/cms/parNewGeneration.hpp"
+
+#define VM_STRUCTS_CMSGC(nonstatic_field, \
+ volatile_nonstatic_field, \
+ static_field) \
nonstatic_field(CompactibleFreeListSpace, _collector, CMSCollector*) \
nonstatic_field(CompactibleFreeListSpace, _bt, BlockOffsetArrayNonContigSpace) \
static_field(CompactibleFreeListSpace, _min_chunk_size_in_bytes, size_t) \
@@ -43,13 +49,22 @@
nonstatic_field(AFLBinaryTreeDictionary, _total_size, size_t) \
nonstatic_field(CompactibleFreeListSpace, _dictionary, AFLBinaryTreeDictionary*) \
nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], AdaptiveFreeList<FreeChunk>) \
- nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock)
+ nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock) \
+ volatile_nonstatic_field(FreeChunk, _size, size_t) \
+ nonstatic_field(FreeChunk, _next, FreeChunk*) \
+ nonstatic_field(FreeChunk, _prev, FreeChunk*) \
+ nonstatic_field(AdaptiveFreeList<FreeChunk>, _size, size_t) \
+ nonstatic_field(AdaptiveFreeList<FreeChunk>, _count, ssize_t)
-#define VM_TYPES_CMS(declare_type, \
- declare_toplevel_type) \
+
+#define VM_TYPES_CMSGC(declare_type, \
+ declare_toplevel_type, \
+ declare_integer_type) \
\
+ declare_type(CMSHeap, GenCollectedHeap) \
declare_type(ConcurrentMarkSweepGeneration,CardGeneration) \
+ declare_type(ParNewGeneration, DefNewGeneration) \
declare_type(CompactibleFreeListSpace, CompactibleSpace) \
declare_type(ConcurrentMarkSweepThread, NamedThread) \
declare_toplevel_type(CMSCollector) \
@@ -61,10 +76,16 @@
declare_toplevel_type(CompactibleFreeListSpace*) \
declare_toplevel_type(CMSCollector*) \
declare_toplevel_type(AFLBinaryTreeDictionary) \
- declare_toplevel_type(LinearAllocBlock)
+ declare_toplevel_type(LinearAllocBlock) \
+ declare_toplevel_type(FreeChunk*) \
+ declare_toplevel_type(AdaptiveFreeList<FreeChunk>*) \
+ declare_toplevel_type(AdaptiveFreeList<FreeChunk>)
-#define VM_INT_CONSTANTS_CMS(declare_constant) \
+
+#define VM_INT_CONSTANTS_CMSGC(declare_constant, \
+ declare_constant_with_value) \
declare_constant(CompactibleFreeListSpace::IndexSetSize) \
declare_constant(Generation::ConcurrentMarkSweep) \
+ declare_constant(Generation::ParNew)
#endif // SHARE_VM_GC_CMS_VMSTRUCTS_CMS_HPP
--- a/src/hotspot/share/gc/cms/vmStructs_parNew.hpp Tue Apr 17 08:54:17 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2006, 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_CMS_VMSTRUCTS_PARNEW_HPP
-#define SHARE_VM_GC_CMS_VMSTRUCTS_PARNEW_HPP
-
-#define VM_TYPES_PARNEW(declare_type) \
- declare_type(ParNewGeneration, DefNewGeneration)
-
-#define VM_INT_CONSTANTS_PARNEW(declare_constant) \
- declare_constant(Generation::ParNew)
-
-#endif // SHARE_VM_GC_CMS_VMSTRUCTS_PARNEW_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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/heapRegionBounds.inline.hpp"
+#include "runtime/commandLineFlagRangeList.hpp"
+#include "runtime/globals_extension.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) {
+ if (!UseG1GC) return Flag::SUCCESS;
+
+ // Default value of G1RSetRegionEntries=0 means will be set ergonomically.
+ // Minimum value is 1.
+ if (FLAG_IS_CMDLINE(G1RSetRegionEntries) && (value < 1)) {
+ CommandLineError::print(verbose,
+ "G1RSetRegionEntries (" INTX_FORMAT ") must be "
+ "greater than or equal to 1\n",
+ value);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) {
+ if (!UseG1GC) return Flag::SUCCESS;
+
+ // Default value of G1RSetSparseRegionEntries=0 means will be set ergonomically.
+ // Minimum value is 1.
+ if (FLAG_IS_CMDLINE(G1RSetSparseRegionEntries) && (value < 1)) {
+ CommandLineError::print(verbose,
+ "G1RSetSparseRegionEntries (" INTX_FORMAT ") must be "
+ "greater than or equal to 1\n",
+ value);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) {
+ if (!UseG1GC) return Flag::SUCCESS;
+
+ // Default value of G1HeapRegionSize=0 means will be set ergonomically.
+ if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < HeapRegionBounds::min_size())) {
+ CommandLineError::print(verbose,
+ "G1HeapRegionSize (" SIZE_FORMAT ") must be "
+ "greater than or equal to ergonomic heap region minimum size\n",
+ value);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) {
+ if (!UseG1GC) return Flag::SUCCESS;
+
+ if (value > G1MaxNewSizePercent) {
+ CommandLineError::print(verbose,
+ "G1NewSizePercent (" UINTX_FORMAT ") must be "
+ "less than or equal to G1MaxNewSizePercent (" UINTX_FORMAT ")\n",
+ value, G1MaxNewSizePercent);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) {
+ if (!UseG1GC) return Flag::SUCCESS;
+
+ if (value < G1NewSizePercent) {
+ CommandLineError::print(verbose,
+ "G1MaxNewSizePercent (" UINTX_FORMAT ") must be "
+ "greater than or equal to G1NewSizePercent (" UINTX_FORMAT ")\n",
+ value, G1NewSizePercent);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose) {
+ if (UseG1GC && FLAG_IS_CMDLINE(MaxGCPauseMillis) && (value >= GCPauseIntervalMillis)) {
+ CommandLineError::print(verbose,
+ "MaxGCPauseMillis (" UINTX_FORMAT ") must be "
+ "less than GCPauseIntervalMillis (" UINTX_FORMAT ")\n",
+ value, GCPauseIntervalMillis);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+
+ return Flag::SUCCESS;
+}
+
+Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose) {
+ if (UseG1GC) {
+ if (FLAG_IS_CMDLINE(GCPauseIntervalMillis)) {
+ if (value < 1) {
+ CommandLineError::print(verbose,
+ "GCPauseIntervalMillis (" UINTX_FORMAT ") must be "
+ "greater than or equal to 1\n",
+ value);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+
+ if (FLAG_IS_DEFAULT(MaxGCPauseMillis)) {
+ CommandLineError::print(verbose,
+ "GCPauseIntervalMillis cannot be set "
+ "without setting MaxGCPauseMillis\n");
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+
+ if (value <= MaxGCPauseMillis) {
+ CommandLineError::print(verbose,
+ "GCPauseIntervalMillis (" UINTX_FORMAT ") must be "
+ "greater than MaxGCPauseMillis (" UINTX_FORMAT ")\n",
+ value, MaxGCPauseMillis);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+ }
+
+ return Flag::SUCCESS;
+}
+
+Flag::Error NewSizeConstraintFuncG1(size_t value, bool verbose) {
+#ifdef _LP64
+ // Overflow would happen for uint type variable of YoungGenSizer::_min_desired_young_length
+ // when the value to be assigned exceeds uint range.
+ // i.e. result of '(uint)(NewSize / region size(1~32MB))'
+ // So maximum of NewSize should be 'max_juint * 1M'
+ if (UseG1GC && (value > (max_juint * 1 * M))) {
+ CommandLineError::print(verbose,
+ "NewSize (" SIZE_FORMAT ") must be less than ergonomic maximum value\n",
+ value);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+#endif // _LP64
+ return Flag::SUCCESS;
+}
+
+size_t MaxSizeForHeapAlignmentG1() {
+ return HeapRegionBounds::max_size();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/commandLineFlagConstraintsG1.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,46 @@
+/*
+ * 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
+ * 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_GC_G1_COMMANDLINEFLAGCONSTRAINTSG1_HPP
+#define SHARE_GC_G1_COMMANDLINEFLAGCONSTRAINTSG1_HPP
+
+#include "runtime/globals.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+// G1 Flag Constraints
+Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose);
+Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose);
+Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose);
+Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose);
+
+// G1 Subconstraints
+Flag::Error MaxGCPauseMillisConstraintFuncG1(uintx value, bool verbose);
+Flag::Error GCPauseIntervalMillisConstraintFuncG1(uintx value, bool verbose);
+Flag::Error MaxSizeForHeapAlignmentG1(const char* name, size_t value, bool verbose);
+Flag::Error NewSizeConstraintFuncG1(size_t value, bool verbose);
+
+size_t MaxSizeForHeapAlignmentG1();
+
+#endif // SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSG1_HPP
--- a/src/hotspot/share/gc/g1/dirtyCardQueue.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/dirtyCardQueue.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -26,6 +26,7 @@
#include "gc/g1/dirtyCardQueue.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1RemSet.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/shared/workgroup.hpp"
#include "runtime/atomic.hpp"
@@ -164,7 +165,7 @@
}
void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) {
- t->dirty_card_queue().handle_zero_index();
+ G1ThreadLocalData::dirty_card_queue(t).handle_zero_index();
}
bool DirtyCardQueueSet::apply_closure_to_buffer(CardTableEntryClosure* cl,
@@ -321,7 +322,7 @@
// Since abandon is done only at safepoints, we can safely manipulate
// these queues.
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
- t->dirty_card_queue().reset();
+ G1ThreadLocalData::dirty_card_queue(t).reset();
}
shared_dirty_card_queue()->reset();
}
@@ -340,7 +341,7 @@
_max_completed_queue = max_jint;
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
- concatenate_log(t->dirty_card_queue());
+ concatenate_log(G1ThreadLocalData::dirty_card_queue(t));
}
concatenate_log(_shared_dirty_card_queue);
// Restore the completed buffer queue limit.
--- a/src/hotspot/share/gc/g1/g1Allocator.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1Allocator.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -33,8 +33,8 @@
#include "gc/g1/heapRegionType.hpp"
#include "utilities/align.hpp"
-G1DefaultAllocator::G1DefaultAllocator(G1CollectedHeap* heap) :
- G1Allocator(heap),
+G1Allocator::G1Allocator(G1CollectedHeap* heap) :
+ _g1h(heap),
_survivor_is_full(false),
_old_is_full(false),
_retained_old_gc_alloc_region(NULL),
@@ -42,16 +42,20 @@
_old_gc_alloc_region(heap->alloc_buffer_stats(InCSetState::Old)) {
}
-void G1DefaultAllocator::init_mutator_alloc_region() {
+void G1Allocator::init_mutator_alloc_region() {
assert(_mutator_alloc_region.get() == NULL, "pre-condition");
_mutator_alloc_region.init();
}
-void G1DefaultAllocator::release_mutator_alloc_region() {
+void G1Allocator::release_mutator_alloc_region() {
_mutator_alloc_region.release();
assert(_mutator_alloc_region.get() == NULL, "post-condition");
}
+bool G1Allocator::is_retained_old_region(HeapRegion* hr) {
+ return _retained_old_gc_alloc_region == hr;
+}
+
void G1Allocator::reuse_retained_old_region(EvacuationInfo& evacuation_info,
OldGCAllocRegion* old,
HeapRegion** retained_old) {
@@ -87,7 +91,7 @@
}
}
-void G1DefaultAllocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info) {
+void G1Allocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info) {
assert_at_safepoint_on_vm_thread();
_survivor_is_full = false;
@@ -100,7 +104,7 @@
&_retained_old_gc_alloc_region);
}
-void G1DefaultAllocator::release_gc_alloc_regions(EvacuationInfo& evacuation_info) {
+void G1Allocator::release_gc_alloc_regions(EvacuationInfo& evacuation_info) {
evacuation_info.set_allocation_regions(survivor_gc_alloc_region()->count() +
old_gc_alloc_region()->count());
survivor_gc_alloc_region()->release();
@@ -112,25 +116,25 @@
_retained_old_gc_alloc_region = old_gc_alloc_region()->release();
}
-void G1DefaultAllocator::abandon_gc_alloc_regions() {
+void G1Allocator::abandon_gc_alloc_regions() {
assert(survivor_gc_alloc_region()->get() == NULL, "pre-condition");
assert(old_gc_alloc_region()->get() == NULL, "pre-condition");
_retained_old_gc_alloc_region = NULL;
}
-bool G1DefaultAllocator::survivor_is_full() const {
+bool G1Allocator::survivor_is_full() const {
return _survivor_is_full;
}
-bool G1DefaultAllocator::old_is_full() const {
+bool G1Allocator::old_is_full() const {
return _old_is_full;
}
-void G1DefaultAllocator::set_survivor_full() {
+void G1Allocator::set_survivor_full() {
_survivor_is_full = true;
}
-void G1DefaultAllocator::set_old_full() {
+void G1Allocator::set_old_full() {
_old_is_full = true;
}
@@ -151,6 +155,19 @@
}
}
+size_t G1Allocator::used_in_alloc_regions() {
+ assert(Heap_lock->owner() != NULL, "Should be owned on this thread's behalf.");
+ size_t result = 0;
+
+ // Read only once in case it is set to NULL concurrently
+ HeapRegion* hr = mutator_alloc_region()->get();
+ if (hr != NULL) {
+ result += hr->used();
+ }
+ return result;
+}
+
+
HeapWord* G1Allocator::par_allocate_during_gc(InCSetState dest,
size_t word_size) {
size_t temp = 0;
@@ -221,13 +238,30 @@
return result;
}
+uint G1PLABAllocator::calc_survivor_alignment_bytes() {
+ assert(SurvivorAlignmentInBytes >= ObjectAlignmentInBytes, "sanity");
+ if (SurvivorAlignmentInBytes == ObjectAlignmentInBytes) {
+ // No need to align objects in the survivors differently, return 0
+ // which means "survivor alignment is not used".
+ return 0;
+ } else {
+ assert(SurvivorAlignmentInBytes > 0, "sanity");
+ return SurvivorAlignmentInBytes;
+ }
+}
+
G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) :
_g1h(G1CollectedHeap::heap()),
_allocator(allocator),
+ _surviving_alloc_buffer(_g1h->desired_plab_sz(InCSetState::Young)),
+ _tenured_alloc_buffer(_g1h->desired_plab_sz(InCSetState::Old)),
_survivor_alignment_bytes(calc_survivor_alignment_bytes()) {
- for (size_t i = 0; i < ARRAY_SIZE(_direct_allocated); i++) {
- _direct_allocated[i] = 0;
+ for (uint state = 0; state < InCSetState::Num; state++) {
+ _direct_allocated[state] = 0;
+ _alloc_buffers[state] = NULL;
}
+ _alloc_buffers[InCSetState::Young] = &_surviving_alloc_buffer;
+ _alloc_buffers[InCSetState::Old] = &_tenured_alloc_buffer;
}
bool G1PLABAllocator::may_throw_away_buffer(size_t const allocation_word_sz, size_t const buffer_size) const {
@@ -282,18 +316,7 @@
alloc_buffer(dest)->undo_allocation(obj, word_sz);
}
-G1DefaultPLABAllocator::G1DefaultPLABAllocator(G1Allocator* allocator) :
- G1PLABAllocator(allocator),
- _surviving_alloc_buffer(_g1h->desired_plab_sz(InCSetState::Young)),
- _tenured_alloc_buffer(_g1h->desired_plab_sz(InCSetState::Old)) {
- for (uint state = 0; state < InCSetState::Num; state++) {
- _alloc_buffers[state] = NULL;
- }
- _alloc_buffers[InCSetState::Young] = &_surviving_alloc_buffer;
- _alloc_buffers[InCSetState::Old] = &_tenured_alloc_buffer;
-}
-
-void G1DefaultPLABAllocator::flush_and_retire_stats() {
+void G1PLABAllocator::flush_and_retire_stats() {
for (uint state = 0; state < InCSetState::Num; state++) {
PLAB* const buf = _alloc_buffers[state];
if (buf != NULL) {
@@ -305,7 +328,7 @@
}
}
-void G1DefaultPLABAllocator::waste(size_t& wasted, size_t& undo_wasted) {
+void G1PLABAllocator::waste(size_t& wasted, size_t& undo_wasted) {
wasted = 0;
undo_wasted = 0;
for (uint state = 0; state < InCSetState::Num; state++) {
--- a/src/hotspot/share/gc/g1/g1Allocator.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1Allocator.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,82 +37,13 @@
// Also keeps track of retained regions across GCs.
class G1Allocator : public CHeapObj<mtGC> {
friend class VMStructs;
-protected:
+
+private:
G1CollectedHeap* _g1h;
- virtual MutatorAllocRegion* mutator_alloc_region() = 0;
-
- virtual bool survivor_is_full() const = 0;
- virtual bool old_is_full() const = 0;
-
- virtual void set_survivor_full() = 0;
- virtual void set_old_full() = 0;
-
- // Accessors to the allocation regions.
- virtual SurvivorGCAllocRegion* survivor_gc_alloc_region() = 0;
- virtual OldGCAllocRegion* old_gc_alloc_region() = 0;
-
- // Allocation attempt during GC for a survivor object / PLAB.
- inline HeapWord* survivor_attempt_allocation(size_t min_word_size,
- size_t desired_word_size,
- size_t* actual_word_size);
- // Allocation attempt during GC for an old object / PLAB.
- inline HeapWord* old_attempt_allocation(size_t min_word_size,
- size_t desired_word_size,
- size_t* actual_word_size);
-public:
- G1Allocator(G1CollectedHeap* heap) : _g1h(heap) { }
- virtual ~G1Allocator() { }
-
-#ifdef ASSERT
- // Do we currently have an active mutator region to allocate into?
- bool has_mutator_alloc_region() { return mutator_alloc_region()->get() != NULL; }
-#endif
- virtual void init_mutator_alloc_region() = 0;
- virtual void release_mutator_alloc_region() = 0;
-
- virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0;
- virtual void release_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0;
- virtual void abandon_gc_alloc_regions() = 0;
-
- // Management of retained regions.
-
- virtual bool is_retained_old_region(HeapRegion* hr) = 0;
- void reuse_retained_old_region(EvacuationInfo& evacuation_info,
- OldGCAllocRegion* old,
- HeapRegion** retained);
-
- // Allocate blocks of memory during mutator time.
-
- inline HeapWord* attempt_allocation(size_t word_size);
- inline HeapWord* attempt_allocation_locked(size_t word_size);
- inline HeapWord* attempt_allocation_force(size_t word_size);
-
- size_t unsafe_max_tlab_alloc();
-
- // Allocate blocks of memory during garbage collection. Will ensure an
- // allocation region, either by picking one or expanding the
- // heap, and then allocate a block of the given size. The block
- // may not be a humongous - it must fit into a single heap region.
- HeapWord* par_allocate_during_gc(InCSetState dest,
- size_t word_size);
-
- HeapWord* par_allocate_during_gc(InCSetState dest,
- size_t min_word_size,
- size_t desired_word_size,
- size_t* actual_word_size);
-
- virtual size_t used_in_alloc_regions() = 0;
-};
-
-// The default allocation region manager for G1. Provides a single mutator, survivor
-// and old generation allocation region.
-// Can retain the (single) old generation allocation region across GCs.
-class G1DefaultAllocator : public G1Allocator {
-private:
bool _survivor_is_full;
bool _old_is_full;
-protected:
+
// Alloc region used to satisfy mutator allocation requests.
MutatorAllocRegion _mutator_alloc_region;
@@ -125,50 +56,67 @@
OldGCAllocRegion _old_gc_alloc_region;
HeapRegion* _retained_old_gc_alloc_region;
-public:
- G1DefaultAllocator(G1CollectedHeap* heap);
+
+ bool survivor_is_full() const;
+ bool old_is_full() const;
- virtual bool survivor_is_full() const;
- virtual bool old_is_full() const ;
+ void set_survivor_full();
+ void set_old_full();
- virtual void set_survivor_full();
- virtual void set_old_full();
+ void reuse_retained_old_region(EvacuationInfo& evacuation_info,
+ OldGCAllocRegion* old,
+ HeapRegion** retained);
- virtual void init_mutator_alloc_region();
- virtual void release_mutator_alloc_region();
+ // Accessors to the allocation regions.
+ inline MutatorAllocRegion* mutator_alloc_region();
+ inline SurvivorGCAllocRegion* survivor_gc_alloc_region();
+ inline OldGCAllocRegion* old_gc_alloc_region();
- virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info);
- virtual void release_gc_alloc_regions(EvacuationInfo& evacuation_info);
- virtual void abandon_gc_alloc_regions();
+ // Allocation attempt during GC for a survivor object / PLAB.
+ HeapWord* survivor_attempt_allocation(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size);
- virtual bool is_retained_old_region(HeapRegion* hr) {
- return _retained_old_gc_alloc_region == hr;
- }
+ // Allocation attempt during GC for an old object / PLAB.
+ HeapWord* old_attempt_allocation(size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size);
+public:
+ G1Allocator(G1CollectedHeap* heap);
- virtual MutatorAllocRegion* mutator_alloc_region() {
- return &_mutator_alloc_region;
- }
+#ifdef ASSERT
+ // Do we currently have an active mutator region to allocate into?
+ bool has_mutator_alloc_region() { return mutator_alloc_region()->get() != NULL; }
+#endif
- virtual SurvivorGCAllocRegion* survivor_gc_alloc_region() {
- return &_survivor_gc_alloc_region;
- }
+ void init_mutator_alloc_region();
+ void release_mutator_alloc_region();
- virtual OldGCAllocRegion* old_gc_alloc_region() {
- return &_old_gc_alloc_region;
- }
+ void init_gc_alloc_regions(EvacuationInfo& evacuation_info);
+ void release_gc_alloc_regions(EvacuationInfo& evacuation_info);
+ void abandon_gc_alloc_regions();
+ bool is_retained_old_region(HeapRegion* hr);
+
+ // Allocate blocks of memory during mutator time.
- virtual size_t used_in_alloc_regions() {
- assert(Heap_lock->owner() != NULL,
- "Should be owned on this thread's behalf.");
- size_t result = 0;
+ inline HeapWord* attempt_allocation(size_t word_size);
+ inline HeapWord* attempt_allocation_locked(size_t word_size);
+ inline HeapWord* attempt_allocation_force(size_t word_size);
+
+ size_t unsafe_max_tlab_alloc();
+ size_t used_in_alloc_regions();
- // Read only once in case it is set to NULL concurrently
- HeapRegion* hr = mutator_alloc_region()->get();
- if (hr != NULL) {
- result += hr->used();
- }
- return result;
- }
+ // Allocate blocks of memory during garbage collection. Will ensure an
+ // allocation region, either by picking one or expanding the
+ // heap, and then allocate a block of the given size. The block
+ // may not be a humongous - it must fit into a single heap region.
+ HeapWord* par_allocate_during_gc(InCSetState dest,
+ size_t word_size);
+
+ HeapWord* par_allocate_during_gc(InCSetState dest,
+ size_t min_word_size,
+ size_t desired_word_size,
+ size_t* actual_word_size);
};
// Manages the PLABs used during garbage collection. Interface for allocation from PLABs.
@@ -176,10 +124,14 @@
// statistics.
class G1PLABAllocator : public CHeapObj<mtGC> {
friend class G1ParScanThreadState;
-protected:
+private:
G1CollectedHeap* _g1h;
G1Allocator* _allocator;
+ PLAB _surviving_alloc_buffer;
+ PLAB _tenured_alloc_buffer;
+ PLAB* _alloc_buffers[InCSetState::Num];
+
// The survivor alignment in effect in bytes.
// == 0 : don't align survivors
// != 0 : align survivors to that alignment
@@ -190,32 +142,18 @@
// Number of words allocated directly (not counting PLAB allocation).
size_t _direct_allocated[InCSetState::Num];
- virtual void flush_and_retire_stats() = 0;
- virtual PLAB* alloc_buffer(InCSetState dest) = 0;
+ void flush_and_retire_stats();
+ inline PLAB* alloc_buffer(InCSetState dest);
// Calculate the survivor space object alignment in bytes. Returns that or 0 if
// there are no restrictions on survivor alignment.
- static uint calc_survivor_alignment_bytes() {
- assert(SurvivorAlignmentInBytes >= ObjectAlignmentInBytes, "sanity");
- if (SurvivorAlignmentInBytes == ObjectAlignmentInBytes) {
- // No need to align objects in the survivors differently, return 0
- // which means "survivor alignment is not used".
- return 0;
- } else {
- assert(SurvivorAlignmentInBytes > 0, "sanity");
- return SurvivorAlignmentInBytes;
- }
- }
-
- HeapWord* allocate_new_plab(InCSetState dest,
- size_t word_sz);
+ static uint calc_survivor_alignment_bytes();
bool may_throw_away_buffer(size_t const allocation_word_sz, size_t const buffer_size) const;
public:
G1PLABAllocator(G1Allocator* allocator);
- virtual ~G1PLABAllocator() { }
- virtual void waste(size_t& wasted, size_t& undo_wasted) = 0;
+ void waste(size_t& wasted, size_t& undo_wasted);
// Allocate word_sz words in dest, either directly into the regions or by
// allocating a new PLAB. Returns the address of the allocated memory, NULL if
@@ -230,42 +168,13 @@
inline HeapWord* plab_allocate(InCSetState dest,
size_t word_sz);
- HeapWord* allocate(InCSetState dest,
- size_t word_sz,
- bool* refill_failed) {
- HeapWord* const obj = plab_allocate(dest, word_sz);
- if (obj != NULL) {
- return obj;
- }
- return allocate_direct_or_new_plab(dest, word_sz, refill_failed);
- }
+ inline HeapWord* allocate(InCSetState dest,
+ size_t word_sz,
+ bool* refill_failed);
void undo_allocation(InCSetState dest, HeapWord* obj, size_t word_sz);
};
-// The default PLAB allocator for G1. Keeps the current (single) PLAB for survivor
-// and old generation allocation.
-class G1DefaultPLABAllocator : public G1PLABAllocator {
- PLAB _surviving_alloc_buffer;
- PLAB _tenured_alloc_buffer;
- PLAB* _alloc_buffers[InCSetState::Num];
-
-public:
- G1DefaultPLABAllocator(G1Allocator* _allocator);
-
- virtual PLAB* alloc_buffer(InCSetState dest) {
- assert(dest.is_valid(),
- "Allocation buffer index out-of-bounds: " CSETSTATE_FORMAT, dest.value());
- assert(_alloc_buffers[dest.value()] != NULL,
- "Allocation buffer is NULL: " CSETSTATE_FORMAT, dest.value());
- return _alloc_buffers[dest.value()];
- }
-
- virtual void flush_and_retire_stats();
-
- virtual void waste(size_t& wasted, size_t& undo_wasted);
-};
-
// G1ArchiveRegionMap is a boolean array used to mark G1 regions as
// archive regions. This allows a quick check for whether an object
// should not be marked because it is in an archive region.
--- a/src/hotspot/share/gc/g1/g1Allocator.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1Allocator.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,21 +29,41 @@
#include "gc/g1/g1AllocRegion.inline.hpp"
#include "gc/shared/plab.inline.hpp"
-HeapWord* G1Allocator::attempt_allocation(size_t word_size) {
+inline MutatorAllocRegion* G1Allocator::mutator_alloc_region() {
+ return &_mutator_alloc_region;
+}
+
+inline SurvivorGCAllocRegion* G1Allocator::survivor_gc_alloc_region() {
+ return &_survivor_gc_alloc_region;
+}
+
+inline OldGCAllocRegion* G1Allocator::old_gc_alloc_region() {
+ return &_old_gc_alloc_region;
+}
+
+inline HeapWord* G1Allocator::attempt_allocation(size_t word_size) {
return mutator_alloc_region()->attempt_allocation(word_size);
}
-HeapWord* G1Allocator::attempt_allocation_locked(size_t word_size) {
+inline HeapWord* G1Allocator::attempt_allocation_locked(size_t word_size) {
HeapWord* result = mutator_alloc_region()->attempt_allocation_locked(word_size);
assert(result != NULL || mutator_alloc_region()->get() == NULL,
"Must not have a mutator alloc region if there is no memory, but is " PTR_FORMAT, p2i(mutator_alloc_region()->get()));
return result;
}
-HeapWord* G1Allocator::attempt_allocation_force(size_t word_size) {
+inline HeapWord* G1Allocator::attempt_allocation_force(size_t word_size) {
return mutator_alloc_region()->attempt_allocation_force(word_size);
}
+inline PLAB* G1PLABAllocator::alloc_buffer(InCSetState dest) {
+ assert(dest.is_valid(),
+ "Allocation buffer index out-of-bounds: " CSETSTATE_FORMAT, dest.value());
+ assert(_alloc_buffers[dest.value()] != NULL,
+ "Allocation buffer is NULL: " CSETSTATE_FORMAT, dest.value());
+ return _alloc_buffers[dest.value()];
+}
+
inline HeapWord* G1PLABAllocator::plab_allocate(InCSetState dest,
size_t word_sz) {
PLAB* buffer = alloc_buffer(dest);
@@ -54,6 +74,16 @@
}
}
+inline HeapWord* G1PLABAllocator::allocate(InCSetState dest,
+ size_t word_sz,
+ bool* refill_failed) {
+ HeapWord* const obj = plab_allocate(dest, word_sz);
+ if (obj != NULL) {
+ return obj;
+ }
+ return allocate_direct_or_new_plab(dest, word_sz, refill_failed);
+}
+
// Create the maps which is used to identify archive objects.
inline void G1ArchiveAllocator::enable_archive_object_check() {
if (_archive_check_enabled) {
--- a/src/hotspot/share/gc/g1/g1BarrierSet.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1BarrierSet.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -27,6 +27,7 @@
#include "gc/g1/g1BarrierSetAssembler.hpp"
#include "gc/g1/g1CardTable.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.hpp"
#include "gc/g1/satbMarkQueue.hpp"
#include "logging/log.hpp"
@@ -37,25 +38,25 @@
#include "runtime/thread.inline.hpp"
#include "utilities/macros.hpp"
+SATBMarkQueueSet G1BarrierSet::_satb_mark_queue_set;
+DirtyCardQueueSet G1BarrierSet::_dirty_card_queue_set;
+
G1BarrierSet::G1BarrierSet(G1CardTable* card_table) :
CardTableBarrierSet(make_barrier_set_assembler<G1BarrierSetAssembler>(),
card_table,
- BarrierSet::FakeRtti(BarrierSet::G1BarrierSet)),
- _dcqs(JavaThread::dirty_card_queue_set())
-{ }
+ BarrierSet::FakeRtti(BarrierSet::G1BarrierSet)) {}
void G1BarrierSet::enqueue(oop pre_val) {
// Nulls should have been already filtered.
assert(oopDesc::is_oop(pre_val, true), "Error");
- if (!JavaThread::satb_mark_queue_set().is_active()) return;
+ if (!_satb_mark_queue_set.is_active()) return;
Thread* thr = Thread::current();
if (thr->is_Java_thread()) {
- JavaThread* jt = (JavaThread*)thr;
- jt->satb_mark_queue().enqueue(pre_val);
+ G1ThreadLocalData::satb_mark_queue(thr).enqueue(pre_val);
} else {
MutexLockerEx x(Shared_SATB_Q_lock, Mutex::_no_safepoint_check_flag);
- JavaThread::satb_mark_queue_set().shared_satb_queue()->enqueue(pre_val);
+ _satb_mark_queue_set.shared_satb_queue()->enqueue(pre_val);
}
}
@@ -76,7 +77,7 @@
template <class T> void
G1BarrierSet::write_ref_array_pre_work(T* dst, size_t count) {
- if (!JavaThread::satb_mark_queue_set().is_active()) return;
+ if (!_satb_mark_queue_set.is_active()) return;
T* elem_ptr = dst;
for (size_t i = 0; i < count; i++, elem_ptr++) {
T heap_oop = RawAccess<>::oop_load(elem_ptr);
@@ -106,12 +107,11 @@
*byte = G1CardTable::dirty_card_val();
Thread* thr = Thread::current();
if (thr->is_Java_thread()) {
- JavaThread* jt = (JavaThread*)thr;
- jt->dirty_card_queue().enqueue(byte);
+ G1ThreadLocalData::dirty_card_queue(thr).enqueue(byte);
} else {
MutexLockerEx x(Shared_DirtyCardQ_lock,
Mutex::_no_safepoint_check_flag);
- _dcqs.shared_dirty_card_queue()->enqueue(byte);
+ _dirty_card_queue_set.shared_dirty_card_queue()->enqueue(byte);
}
}
}
@@ -130,14 +130,13 @@
OrderAccess::storeload();
// Enqueue if necessary.
if (thr->is_Java_thread()) {
- JavaThread* jt = (JavaThread*)thr;
for (; byte <= last_byte; byte++) {
if (*byte == G1CardTable::g1_young_card_val()) {
continue;
}
if (*byte != G1CardTable::dirty_card_val()) {
*byte = G1CardTable::dirty_card_val();
- jt->dirty_card_queue().enqueue(byte);
+ G1ThreadLocalData::dirty_card_queue(thr).enqueue(byte);
}
}
} else {
@@ -149,13 +148,23 @@
}
if (*byte != G1CardTable::dirty_card_val()) {
*byte = G1CardTable::dirty_card_val();
- _dcqs.shared_dirty_card_queue()->enqueue(byte);
+ _dirty_card_queue_set.shared_dirty_card_queue()->enqueue(byte);
}
}
}
}
}
+void G1BarrierSet::on_thread_create(Thread* thread) {
+ // Create thread local data
+ G1ThreadLocalData::create(thread);
+}
+
+void G1BarrierSet::on_thread_destroy(Thread* thread) {
+ // Destroy thread local data
+ G1ThreadLocalData::destroy(thread);
+}
+
void G1BarrierSet::on_thread_attach(JavaThread* thread) {
// This method initializes the SATB and dirty card queues before a
// JavaThread is added to the Java thread list. Right now, we don't
@@ -175,20 +184,20 @@
// thread being added to the Java thread list (an example of this is
// when the structure for the DestroyJavaVM thread is created).
assert(!SafepointSynchronize::is_at_safepoint(), "We should not be at a safepoint");
- assert(!thread->satb_mark_queue().is_active(), "SATB queue should not be active");
- assert(thread->satb_mark_queue().is_empty(), "SATB queue should be empty");
- assert(thread->dirty_card_queue().is_active(), "Dirty card queue should be active");
+ assert(!G1ThreadLocalData::satb_mark_queue(thread).is_active(), "SATB queue should not be active");
+ assert(G1ThreadLocalData::satb_mark_queue(thread).is_empty(), "SATB queue should be empty");
+ assert(G1ThreadLocalData::dirty_card_queue(thread).is_active(), "Dirty card queue should be active");
// If we are creating the thread during a marking cycle, we should
// set the active field of the SATB queue to true.
- if (thread->satb_mark_queue_set().is_active()) {
- thread->satb_mark_queue().set_active(true);
+ if (_satb_mark_queue_set.is_active()) {
+ G1ThreadLocalData::satb_mark_queue(thread).set_active(true);
}
}
void G1BarrierSet::on_thread_detach(JavaThread* thread) {
// Flush any deferred card marks, SATB buffers and dirty card queue buffers
CardTableBarrierSet::on_thread_detach(thread);
- thread->satb_mark_queue().flush();
- thread->dirty_card_queue().flush();
+ G1ThreadLocalData::satb_mark_queue(thread).flush();
+ G1ThreadLocalData::dirty_card_queue(thread).flush();
}
--- a/src/hotspot/share/gc/g1/g1BarrierSet.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1BarrierSet.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,6 +25,8 @@
#ifndef SHARE_VM_GC_G1_G1BARRIERSET_HPP
#define SHARE_VM_GC_G1_G1BARRIERSET_HPP
+#include "gc/g1/dirtyCardQueue.hpp"
+#include "gc/g1/satbMarkQueue.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
class DirtyCardQueueSet;
@@ -37,7 +39,8 @@
class G1BarrierSet: public CardTableBarrierSet {
friend class VMStructs;
private:
- DirtyCardQueueSet& _dcqs;
+ static SATBMarkQueueSet _satb_mark_queue_set;
+ static DirtyCardQueueSet _dirty_card_queue_set;
public:
G1BarrierSet(G1CardTable* table);
@@ -71,9 +74,19 @@
void write_ref_field_post(T* field, oop new_val);
void write_ref_field_post_slow(volatile jbyte* byte);
+ virtual void on_thread_create(Thread* thread);
+ virtual void on_thread_destroy(Thread* thread);
virtual void on_thread_attach(JavaThread* thread);
virtual void on_thread_detach(JavaThread* thread);
+ static SATBMarkQueueSet& satb_mark_queue_set() {
+ return _satb_mark_queue_set;
+ }
+
+ static DirtyCardQueueSet& dirty_card_queue_set() {
+ return _dirty_card_queue_set;
+ }
+
// Callbacks for runtime accesses.
template <DecoratorSet decorators, typename BarrierSetT = G1BarrierSet>
class AccessBarrier: public ModRefBarrierSet::AccessBarrier<decorators, BarrierSetT> {
--- a/src/hotspot/share/gc/g1/g1BarrierSetAssembler.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1BarrierSetAssembler.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -22,11 +22,11 @@
*
*/
-#ifndef SHARE_GC_SHARED_G1BARRIERSETASSEMBLER_HPP
-#define SHARE_GC_SHARED_G1BARRIERSETASSEMBLER_HPP
+#ifndef SHARE_GC_G1_G1BARRIERSETASSEMBLER_HPP
+#define SHARE_GC_G1_G1BARRIERSETASSEMBLER_HPP
#include "utilities/macros.hpp"
#include CPU_HEADER(gc/g1/g1BarrierSetAssembler)
-#endif // SHARE_GC_SHARED_G1BARRIERSETASSEMBLER_HPP
+#endif // SHARE_GC_G1_G1BARRIERSETASSEMBLER_HPP
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,6 +30,7 @@
#include "code/icBuffer.hpp"
#include "gc/g1/bufferingOopClosure.hpp"
#include "gc/g1/g1Allocator.inline.hpp"
+#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectionSet.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
@@ -53,6 +54,7 @@
#include "gc/g1/g1RootClosures.hpp"
#include "gc/g1/g1RootProcessor.hpp"
#include "gc/g1/g1StringDedup.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/g1YCTypes.hpp"
#include "gc/g1/g1YoungRemSetSamplingThread.hpp"
#include "gc/g1/heapRegion.inline.hpp"
@@ -1036,7 +1038,7 @@
}
// Discard all remembered set updates.
- JavaThread::dirty_card_queue_set().abandon_logs();
+ G1BarrierSet::dirty_card_queue_set().abandon_logs();
assert(dirty_card_queue_set().completed_buffers_num() == 0, "DCQS should be empty");
}
@@ -1426,7 +1428,7 @@
_workers->initialize_workers();
_verifier = new G1HeapVerifier(this);
- _allocator = new G1DefaultAllocator(this);
+ _allocator = new G1Allocator(this);
_heap_sizing_policy = G1HeapSizingPolicy::create(this, _g1_policy->analytics());
@@ -1540,7 +1542,7 @@
G1BarrierSet* bs = new G1BarrierSet(ct);
bs->initialize();
assert(bs->is_a(BarrierSet::G1BarrierSet), "sanity");
- set_barrier_set(bs);
+ BarrierSet::set_barrier_set(bs);
_card_table = ct;
// Create the hot card cache.
@@ -1625,7 +1627,7 @@
vm_shutdown_during_initialization("Could not create/initialize G1ConcurrentMark");
return JNI_ENOMEM;
}
- _cmThread = _cm->cm_thread();
+ _cm_thread = _cm->cm_thread();
// Now expand into the initial heap size.
if (!expand(init_byte_size, _workers)) {
@@ -1636,10 +1638,10 @@
// Perform any initialization actions delegated to the policy.
g1_policy()->init(this, &_collection_set);
- JavaThread::satb_mark_queue_set().initialize(SATB_Q_CBL_mon,
- SATB_Q_FL_lock,
- G1SATBProcessCompletedThreshold,
- Shared_SATB_Q_lock);
+ G1BarrierSet::satb_mark_queue_set().initialize(SATB_Q_CBL_mon,
+ SATB_Q_FL_lock,
+ G1SATBProcessCompletedThreshold,
+ Shared_SATB_Q_lock);
jint ecode = initialize_concurrent_refinement();
if (ecode != JNI_OK) {
@@ -1651,20 +1653,20 @@
return ecode;
}
- JavaThread::dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
- DirtyCardQ_FL_lock,
- (int)concurrent_refine()->yellow_zone(),
- (int)concurrent_refine()->red_zone(),
- Shared_DirtyCardQ_lock,
- NULL, // fl_owner
- true); // init_free_ids
+ G1BarrierSet::dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
+ DirtyCardQ_FL_lock,
+ (int)concurrent_refine()->yellow_zone(),
+ (int)concurrent_refine()->red_zone(),
+ Shared_DirtyCardQ_lock,
+ NULL, // fl_owner
+ true); // init_free_ids
dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
DirtyCardQ_FL_lock,
-1, // never trigger processing
-1, // no limit on length
Shared_DirtyCardQ_lock,
- &JavaThread::dirty_card_queue_set());
+ &G1BarrierSet::dirty_card_queue_set());
// Here we allocate the dummy HeapRegion that is required by the
// G1AllocRegion class.
@@ -1714,7 +1716,7 @@
// that are destroyed during shutdown.
_cr->stop();
_young_gen_sampling_thread->stop();
- _cmThread->stop();
+ _cm_thread->stop();
if (G1StringDedup::is_enabled()) {
G1StringDedup::stop();
}
@@ -1833,7 +1835,7 @@
}
void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl, uint worker_i) {
- DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
size_t n_completed_buffers = 0;
while (dcqs.apply_closure_during_gc(cl, worker_i)) {
n_completed_buffers++;
@@ -1967,7 +1969,7 @@
// is set) so that if a waiter requests another System.gc() it doesn't
// incorrectly see that a marking cycle is still in progress.
if (concurrent) {
- _cmThread->set_idle();
+ _cm_thread->set_idle();
}
// This notify_all() will ensure that a thread that called
@@ -2178,11 +2180,11 @@
}
const char* const* G1CollectedHeap::concurrent_phases() const {
- return _cmThread->concurrent_phases();
+ return _cm_thread->concurrent_phases();
}
bool G1CollectedHeap::request_concurrent_phase(const char* phase) {
- return _cmThread->request_concurrent_phase(phase);
+ return _cm_thread->request_concurrent_phase(phase);
}
class PrintRegionClosure: public HeapRegionClosure {
@@ -2272,7 +2274,7 @@
void G1CollectedHeap::print_gc_threads_on(outputStream* st) const {
workers()->print_worker_threads_on(st);
- _cmThread->print_on(st);
+ _cm_thread->print_on(st);
st->cr();
_cm->print_worker_threads_on(st);
_cr->print_threads_on(st);
@@ -2284,7 +2286,7 @@
void G1CollectedHeap::gc_threads_do(ThreadClosure* tc) const {
workers()->threads_do(tc);
- tc->do_thread(_cmThread);
+ tc->do_thread(_cm_thread);
_cm->threads_do(tc);
_cr->threads_do(tc);
tc->do_thread(_young_gen_sampling_thread);
@@ -2455,8 +2457,8 @@
void G1CollectedHeap::do_concurrent_mark() {
MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
- if (!_cmThread->in_progress()) {
- _cmThread->set_started();
+ if (!_cm_thread->in_progress()) {
+ _cm_thread->set_started();
CGC_lock->notify();
}
}
@@ -2464,10 +2466,10 @@
size_t G1CollectedHeap::pending_card_num() {
size_t extra_cards = 0;
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *curr = jtiwh.next(); ) {
- DirtyCardQueue& dcq = curr->dirty_card_queue();
+ DirtyCardQueue& dcq = G1ThreadLocalData::dirty_card_queue(curr);
extra_cards += dcq.size();
}
- DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
size_t buffer_size = dcqs.buffer_size();
size_t buffer_num = dcqs.completed_buffers_num();
@@ -2551,7 +2553,7 @@
RegisterHumongousWithInCSetFastTestClosure()
: _total_humongous(0),
_candidate_humongous(0),
- _dcq(&JavaThread::dirty_card_queue_set()) {
+ _dcq(&G1BarrierSet::dirty_card_queue_set()) {
}
virtual bool do_heap_region(HeapRegion* r) {
@@ -2752,7 +2754,7 @@
_verifier->verify_dirty_young_regions();
// We should not be doing initial mark unless the conc mark thread is running
- if (!_cmThread->should_terminate()) {
+ if (!_cm_thread->should_terminate()) {
// This call will decide whether this pause is an initial-mark
// pause. If it is, in_initial_mark_gc() will return true
// for the duration of this pause.
@@ -2840,11 +2842,7 @@
// reference processing currently works in G1.
// Enable discovery in the STW reference processor
- if (g1_policy()->should_process_references()) {
- ref_processor_stw()->enable_discovery();
- } else {
- ref_processor_stw()->disable_discovery();
- }
+ ref_processor_stw()->enable_discovery();
{
// We want to temporarily turn off discovery by the
@@ -3627,7 +3625,7 @@
dirty_card_queue_set().reset_for_par_iteration();
workers()->run_task(&redirty_task);
- DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set();
+ DirtyCardQueueSet& dcq = G1BarrierSet::dirty_card_queue_set();
dcq.merge_bufferlists(&dirty_card_queue_set());
assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
@@ -4193,12 +4191,8 @@
// as we may have to copy some 'reachable' referent
// objects (and their reachable sub-graphs) that were
// not copied during the pause.
- if (g1_policy()->should_process_references()) {
- preserve_cm_referents(per_thread_states);
- process_discovered_references(per_thread_states);
- } else {
- ref_processor_stw()->verify_no_references_recorded();
- }
+ preserve_cm_referents(per_thread_states);
+ process_discovered_references(per_thread_states);
G1STWIsAliveClosure is_alive(this);
G1KeepAliveClosure keep_alive(this);
@@ -4241,11 +4235,7 @@
// will log these updates (and dirty their associated
// cards). We need these updates logged to update any
// RSets.
- if (g1_policy()->should_process_references()) {
- enqueue_discovered_references(per_thread_states);
- } else {
- g1_policy()->phase_times()->record_ref_enq_time(0);
- }
+ enqueue_discovered_references(per_thread_states);
_allocator->release_gc_alloc_regions(evacuation_info);
@@ -4691,7 +4681,13 @@
obj->is_typeArray()
);
- g1h->concurrent_mark()->humongous_object_eagerly_reclaimed(r);
+ G1ConcurrentMark* const cm = g1h->concurrent_mark();
+ cm->humongous_object_eagerly_reclaimed(r);
+ assert(!cm->is_marked_in_prev_bitmap(obj) && !cm->is_marked_in_next_bitmap(obj),
+ "Eagerly reclaimed humongous region %u should not be marked at all but is in prev %s next %s",
+ region_idx,
+ BOOL_TO_STR(cm->is_marked_in_prev_bitmap(obj)),
+ BOOL_TO_STR(cm->is_marked_in_next_bitmap(obj)));
_humongous_objects_reclaimed++;
do {
HeapRegion* next = g1h->next_region_in_humongous(r);
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -766,7 +766,7 @@
// The concurrent marker (and the thread it runs in.)
G1ConcurrentMark* _cm;
- G1ConcurrentMarkThread* _cmThread;
+ G1ConcurrentMarkThread* _cm_thread;
// The concurrent refiner.
G1ConcurrentRefine* _cr;
@@ -1253,7 +1253,7 @@
// bitmap off to the side.
void do_concurrent_mark();
- bool isMarkedNext(oop obj) const;
+ bool is_marked_next(oop obj) const;
// Determine if an object is dead, given the object and also
// the region to which the object belongs. An object is dead
@@ -1271,7 +1271,7 @@
bool is_obj_ill(const oop obj, const HeapRegion* hr) const {
return
!hr->obj_allocated_since_next_marking(obj) &&
- !isMarkedNext(obj) &&
+ !is_marked_next(obj) &&
!hr->is_archive();
}
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -120,7 +120,7 @@
return _task_queues->queue(i);
}
-inline bool G1CollectedHeap::isMarkedNext(oop obj) const {
+inline bool G1CollectedHeap::is_marked_next(oop obj) const {
return _cm->next_mark_bitmap()->is_marked((HeapWord*)obj);
}
@@ -242,7 +242,7 @@
}
inline bool G1CollectedHeap::is_obj_dead_full(const oop obj, const HeapRegion* hr) const {
- return !isMarkedNext(obj) && !hr->is_archive();
+ return !is_marked_next(obj) && !hr->is_archive();
}
inline bool G1CollectedHeap::is_obj_dead_full(const oop obj) const {
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -26,6 +26,7 @@
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/symbolTable.hpp"
#include "code/codeCache.hpp"
+#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1ConcurrentMark.inline.hpp"
@@ -35,6 +36,7 @@
#include "gc/g1/g1Policy.hpp"
#include "gc/g1/g1RegionMarkStatsCache.inline.hpp"
#include "gc/g1/g1StringDedup.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
#include "gc/g1/heapRegionSet.inline.hpp"
@@ -405,7 +407,7 @@
assert(CGC_lock != NULL, "CGC_lock must be initialized");
- SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set();
+ SATBMarkQueueSet& satb_qs = G1BarrierSet::satb_mark_queue_set();
satb_qs.set_buffer_size(G1SATBBufferSize);
_root_regions.init(_g1h->survivor(), this);
@@ -530,13 +532,18 @@
}
}
+static void clear_mark_if_set(G1CMBitMap* bitmap, HeapWord* addr) {
+ if (bitmap->is_marked(addr)) {
+ bitmap->clear(addr);
+ }
+}
+
void G1ConcurrentMark::humongous_object_eagerly_reclaimed(HeapRegion* r) {
assert_at_safepoint_on_vm_thread();
- // Need to clear mark bit of the humongous object.
- if (_next_mark_bitmap->is_marked(r->bottom())) {
- _next_mark_bitmap->clear(r->bottom());
- }
+ // Need to clear all mark bits of the humongous object.
+ clear_mark_if_set(_prev_mark_bitmap, r->bottom());
+ clear_mark_if_set(_next_mark_bitmap, r->bottom());
if (!_g1h->collector_state()->mark_or_rebuild_in_progress()) {
return;
@@ -757,7 +764,7 @@
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();
+ SATBMarkQueueSet& satb_mq_set = G1BarrierSet::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 */
@@ -1068,7 +1075,7 @@
if (mark_finished) {
weak_refs_work(false /* clear_all_soft_refs */);
- SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
+ SATBMarkQueueSet& satb_mq_set = G1BarrierSet::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.
@@ -1686,11 +1693,11 @@
// 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);
+ G1ThreadLocalData::satb_mark_queue(jt).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);
+ G1BarrierSet::satb_mark_queue_set().shared_satb_queue()->apply_closure_and_empty(&_cm_satb_cl);
}
}
}
@@ -1750,7 +1757,7 @@
_g1h->workers()->run_task(&remarkTask);
}
- SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
+ SATBMarkQueueSet& satb_mq_set = G1BarrierSet::satb_mark_queue_set();
guarantee(has_overflown() ||
satb_mq_set.completed_buffers_num() == 0,
"Invariant: has_overflown = %s, num buffers = " SIZE_FORMAT,
@@ -1932,7 +1939,7 @@
_second_overflow_barrier_sync.abort();
_has_aborted = true;
- SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
+ SATBMarkQueueSet& satb_mq_set = G1BarrierSet::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.
@@ -2142,7 +2149,7 @@
// (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();
+ SATBMarkQueueSet& satb_mq_set = G1BarrierSet::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
@@ -2297,7 +2304,7 @@
_draining_satb_buffers = true;
G1CMSATBBufferClosure satb_cl(this, _g1h);
- SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
+ SATBMarkQueueSet& satb_mq_set = G1BarrierSet::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.
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -589,6 +589,8 @@
inline bool mark_in_next_bitmap(uint worker_id, HeapRegion* const hr, oop const obj, size_t const obj_size = 0);
inline bool mark_in_next_bitmap(uint worker_id, oop const obj, size_t const obj_size = 0);
+ inline bool is_marked_in_next_bitmap(oop p) const;
+
// Returns true if initialization was successfully completed.
bool completed_initialization() const {
return _completed_initialization;
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -255,6 +255,11 @@
return _prev_mark_bitmap->is_marked((HeapWord*)p);
}
+bool G1ConcurrentMark::is_marked_in_next_bitmap(oop p) const {
+ assert(p != NULL && oopDesc::is_oop(p), "expected an oop");
+ return _next_mark_bitmap->is_marked((HeapWord*)p);
+}
+
inline bool G1ConcurrentMark::do_yield_check() {
if (SuspendibleThreadSet::should_yield()) {
SuspendibleThreadSet::yield();
--- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* 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/g1/g1BarrierSet.hpp"
#include "gc/g1/g1ConcurrentRefine.hpp"
#include "gc/g1/g1ConcurrentRefineThread.hpp"
#include "logging/log.hpp"
@@ -377,7 +378,7 @@
void G1ConcurrentRefine::adjust(double update_rs_time,
size_t update_rs_processed_buffers,
double goal_ms) {
- DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
if (G1UseAdaptiveConcRefinement) {
update_zones(update_rs_time, update_rs_processed_buffers, goal_ms);
@@ -425,7 +426,7 @@
}
bool G1ConcurrentRefine::do_refinement_step(uint worker_id) {
- DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
size_t curr_buffer_num = dcqs.completed_buffers_num();
// If the number of the buffers falls down into the yellow zone,
--- a/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineThread.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* 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/g1/g1BarrierSet.hpp"
#include "gc/g1/g1ConcurrentRefine.hpp"
#include "gc/g1/g1ConcurrentRefineThread.hpp"
#include "gc/shared/suspendibleThreadSet.hpp"
@@ -63,7 +64,7 @@
}
bool G1ConcurrentRefineThread::is_active() {
- DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
return is_primary() ? dcqs.process_completed_buffers() : _active;
}
@@ -72,7 +73,7 @@
if (!is_primary()) {
set_active(true);
} else {
- DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
dcqs.set_process_completed(true);
}
_monitor->notify();
@@ -83,7 +84,7 @@
if (!is_primary()) {
set_active(false);
} else {
- DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
dcqs.set_process_completed(false);
}
}
@@ -101,7 +102,7 @@
size_t buffers_processed = 0;
log_debug(gc, refine)("Activated worker %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT,
_worker_id, _cr->activation_threshold(_worker_id),
- JavaThread::dirty_card_queue_set().completed_buffers_num());
+ G1BarrierSet::dirty_card_queue_set().completed_buffers_num());
{
SuspendibleThreadSetJoiner sts_join;
@@ -123,7 +124,7 @@
log_debug(gc, refine)("Deactivated worker %d, off threshold: " SIZE_FORMAT
", current: " SIZE_FORMAT ", processed: " SIZE_FORMAT,
_worker_id, _cr->deactivation_threshold(_worker_id),
- JavaThread::dirty_card_queue_set().completed_buffers_num(),
+ G1BarrierSet::dirty_card_queue_set().completed_buffers_num(),
buffers_processed);
if (os::supports_vtime()) {
--- a/src/hotspot/share/gc/g1/g1EvacFailure.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1EvacFailure.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -36,6 +36,7 @@
#include "gc/shared/preservedMarks.inline.hpp"
#include "oops/access.inline.hpp"
#include "oops/compressedOops.inline.hpp"
+#include "oops/oop.inline.hpp"
class UpdateRSetDeferred : public ExtendedOopClosure {
private:
--- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
* 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 @@
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/shared/gcTraceTime.inline.hpp"
#include "logging/log.hpp"
+#include "oops/oop.inline.hpp"
#include "utilities/ticks.inline.hpp"
class G1ResetHumongousClosure : public HeapRegionClosure {
@@ -47,7 +48,7 @@
if (_bitmap->is_marked(obj)) {
// Clear bitmap and fix mark word.
_bitmap->clear(obj);
- obj->init_mark();
+ obj->init_mark_raw();
} else {
assert(current->is_empty(), "Should have been cleared in phase 2.");
}
@@ -70,7 +71,7 @@
HeapWord* obj_addr = (HeapWord*) obj;
assert(obj_addr != destination, "everything in this pass should be moving");
Copy::aligned_conjoint_words(obj_addr, destination, size);
- oop(destination)->init_mark();
+ oop(destination)->init_mark_raw();
assert(oop(destination)->klass() != NULL, "should have a class");
return size;
--- a/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -112,15 +112,15 @@
// with BiasedLocking, in this case forwardee() will return NULL
// even if the mark-word is used. This is no problem since
// forwardee() will return NULL in the compaction phase as well.
- object->init_mark();
+ object->init_mark_raw();
} else {
// Make sure object has the correct mark-word set or that it will be
// fixed when restoring the preserved marks.
- assert(object->mark() == markOopDesc::prototype_for_object(object) || // Correct mark
- object->mark()->must_be_preserved(object) || // Will be restored by PreservedMarksSet
- (UseBiasedLocking && object->has_bias_pattern()), // Will be restored by BiasedLocking
+ assert(object->mark_raw() == markOopDesc::prototype_for_object(object) || // Correct mark
+ object->mark_raw()->must_be_preserved(object) || // Will be restored by PreservedMarksSet
+ (UseBiasedLocking && object->has_bias_pattern_raw()), // Will be restored by BiasedLocking
"should have correct prototype obj: " PTR_FORMAT " mark: " PTR_FORMAT " prototype: " PTR_FORMAT,
- p2i(object), p2i(object->mark()), p2i(markOopDesc::prototype_for_object(object)));
+ p2i(object), p2i(object->mark_raw()), p2i(markOopDesc::prototype_for_object(object)));
}
assert(object->forwardee() == NULL, "should be forwarded to NULL");
}
--- a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
* 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,7 @@
#include "gc/shared/preservedMarks.inline.hpp"
#include "oops/access.inline.hpp"
#include "oops/compressedOops.inline.hpp"
+#include "oops/oop.inline.hpp"
#include "utilities/debug.hpp"
inline bool G1FullGCMarker::mark_object(oop obj) {
@@ -48,7 +49,7 @@
}
// Marked by us, preserve if needed.
- markOop mark = obj->mark();
+ markOop mark = obj->mark_raw();
if (mark->must_be_preserved(obj) &&
!G1ArchiveAllocator::is_open_archive_object(obj)) {
preserved_stack()->push(obj, mark);
--- a/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,6 +30,7 @@
#include "logging/logStream.hpp"
#include "oops/access.inline.hpp"
#include "oops/compressedOops.inline.hpp"
+#include "oops/oop.inline.hpp"
void G1MarkAndPushClosure::do_oop(oop* p) {
do_oop_nv(p);
--- a/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -33,6 +33,7 @@
#include "memory/iterator.inline.hpp"
#include "oops/access.inline.hpp"
#include "oops/compressedOops.inline.hpp"
+#include "oops/oop.inline.hpp"
template <typename T>
inline void G1MarkAndPushClosure::do_oop_nv(T* p) {
@@ -67,11 +68,11 @@
oop forwardee = obj->forwardee();
if (forwardee == NULL) {
// Not forwarded, return current reference.
- assert(obj->mark() == markOopDesc::prototype_for_object(obj) || // Correct mark
- obj->mark()->must_be_preserved(obj) || // Will be restored by PreservedMarksSet
- (UseBiasedLocking && obj->has_bias_pattern()), // Will be restored by BiasedLocking
+ assert(obj->mark_raw() == markOopDesc::prototype_for_object(obj) || // Correct mark
+ obj->mark_raw()->must_be_preserved(obj) || // Will be restored by PreservedMarksSet
+ (UseBiasedLocking && obj->has_bias_pattern_raw()), // Will be restored by BiasedLocking
"Must have correct prototype or be preserved, obj: " PTR_FORMAT ", mark: " PTR_FORMAT ", prototype: " PTR_FORMAT,
- p2i(obj), p2i(obj->mark()), p2i(markOopDesc::prototype_for_object(obj)));
+ p2i(obj), p2i(obj->mark_raw()), p2i(markOopDesc::prototype_for_object(obj)));
return;
}
--- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -35,6 +35,7 @@
#include "gc/shared/gcTraceTime.inline.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "logging/log.hpp"
+#include "oops/oop.inline.hpp"
#include "utilities/ticks.inline.hpp"
bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) {
--- a/src/hotspot/share/gc/g1/g1HeapVerifier.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1HeapVerifier.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,6 +28,7 @@
#include "gc/g1/heapRegionSet.hpp"
#include "memory/allocation.hpp"
#include "memory/universe.hpp"
+#include "utilities/macros.hpp"
class G1CollectedHeap;
@@ -37,9 +38,6 @@
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:
@@ -76,15 +74,8 @@
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
+ // list verification in debug builds.
+ void verify_region_sets_optional() { DEBUG_ONLY(verify_region_sets();) }
void prepare_for_verify();
double verify(G1VerifyType type, VerifyOption vo, const char* msg);
--- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -36,6 +36,7 @@
#include "oops/access.inline.hpp"
#include "oops/compressedOops.inline.hpp"
#include "oops/oopsHierarchy.hpp"
+#include "oops/oop.inline.hpp"
#include "runtime/prefetch.inline.hpp"
template <class T>
@@ -45,8 +46,8 @@
// stall. We'll try to prefetch the object (for write, given that
// we might need to install the forwarding reference) and we'll
// get back to it when pop it from the queue
- Prefetch::write(obj->mark_addr(), 0);
- Prefetch::read(obj->mark_addr(), (HeapWordSize*2));
+ Prefetch::write(obj->mark_addr_raw(), 0);
+ Prefetch::read(obj->mark_addr_raw(), (HeapWordSize*2));
// slightly paranoid test; I'm trying to catch potential
// problems before we go into push_on_queue to know where the
@@ -240,14 +241,14 @@
const InCSetState state = _g1->in_cset_state(obj);
if (state.is_in_cset()) {
oop forwardee;
- markOop m = obj->mark();
+ markOop m = obj->mark_raw();
if (m->is_marked()) {
forwardee = (oop) m->decode_pointer();
} else {
forwardee = _par_scan_state->copy_to_survivor_space(state, obj, m);
}
assert(forwardee != NULL, "forwardee should not be NULL");
- RawAccess<>::oop_store(p, forwardee);
+ RawAccess<OOP_NOT_NULL>::oop_store(p, forwardee);
if (do_mark_object != G1MarkNone && forwardee != obj) {
// If the object is self-forwarded we don't need to explicitly
// mark it, the evacuation failure protocol will do so.
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -66,7 +66,7 @@
_surviving_young_words = _surviving_young_words_base + PADDING_ELEM_NUM;
memset(_surviving_young_words, 0, real_length * sizeof(size_t));
- _plab_allocator = new G1DefaultPLABAllocator(_g1h->allocator());
+ _plab_allocator = new G1PLABAllocator(_g1h->allocator());
_dest[InCSetState::NotInCSet] = InCSetState::NotInCSet;
// The dest for Young is used when the objects are aged enough to
@@ -282,15 +282,15 @@
// In this case, we have to install the mark word first,
// otherwise obj looks to be forwarded (the old mark word,
// which contains the forward pointer, was copied)
- obj->set_mark(old_mark);
+ obj->set_mark_raw(old_mark);
markOop new_mark = old_mark->displaced_mark_helper()->set_age(age);
old_mark->set_displaced_mark_helper(new_mark);
} else {
- obj->set_mark(old_mark->set_age(age));
+ obj->set_mark_raw(old_mark->set_age(age));
}
_age_table.add(age, word_sz);
} else {
- obj->set_mark(old_mark);
+ obj->set_mark_raw(old_mark);
}
if (G1StringDedup::is_enabled()) {
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -161,9 +161,10 @@
inline void do_oop_partial_array(oop* p);
// This method is applied to the fields of the objects that have just been copied.
- template <class T> inline void do_oop_evac(T* p, HeapRegion* from);
+ template <class T> inline void do_oop_evac(T* p);
- template <class T> inline void deal_with_reference(T* ref_to_scan);
+ inline void deal_with_reference(oop* ref_to_scan);
+ inline void deal_with_reference(narrowOop* ref_to_scan);
inline void dispatch_reference(StarTask ref);
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,32 +30,34 @@
#include "oops/access.inline.hpp"
#include "oops/oop.inline.hpp"
-template <class T> void G1ParScanThreadState::do_oop_evac(T* p, HeapRegion* from) {
+template <class T> void G1ParScanThreadState::do_oop_evac(T* p) {
// Reference should not be NULL here as such are never pushed to the task queue.
oop obj = RawAccess<OOP_NOT_NULL>::oop_load(p);
// Although we never intentionally push references outside of the collection
// set, due to (benign) races in the claim mechanism during RSet scanning more
// than one thread might claim the same card. So the same card may be
- // processed multiple times. So redo this check.
+ // processed multiple times, and so we might get references into old gen here.
+ // So we need to redo this check.
const InCSetState in_cset_state = _g1h->in_cset_state(obj);
if (in_cset_state.is_in_cset()) {
- markOop m = obj->mark();
+ markOop m = obj->mark_raw();
if (m->is_marked()) {
obj = (oop) m->decode_pointer();
} else {
obj = copy_to_survivor_space(in_cset_state, obj, m);
}
- RawAccess<>::oop_store(p, obj);
+ RawAccess<OOP_NOT_NULL>::oop_store(p, obj);
} else if (in_cset_state.is_humongous()) {
_g1h->set_humongous_is_live(obj);
} else {
assert(in_cset_state.is_default(),
- "In_cset_state must be NotInCSet here, but is " CSETSTATE_FORMAT, in_cset_state.value());
+ "In_cset_state must be NotInCSet here, but is " CSETSTATE_FORMAT, in_cset_state.value());
}
assert(obj != NULL, "Must be");
if (!HeapRegion::is_in_same_region(p, obj)) {
+ HeapRegion* from = _g1h->heap_region_containing(p);
update_rs(from, p, obj);
}
}
@@ -114,15 +116,19 @@
to_obj_array->oop_iterate_range(&_scanner, start, end);
}
-template <class T> inline void G1ParScanThreadState::deal_with_reference(T* ref_to_scan) {
+inline void G1ParScanThreadState::deal_with_reference(oop* ref_to_scan) {
if (!has_partial_array_mask(ref_to_scan)) {
- HeapRegion* r = _g1h->heap_region_containing(ref_to_scan);
- do_oop_evac(ref_to_scan, r);
+ do_oop_evac(ref_to_scan);
} else {
- do_oop_partial_array((oop*)ref_to_scan);
+ do_oop_partial_array(ref_to_scan);
}
}
+inline void G1ParScanThreadState::deal_with_reference(narrowOop* ref_to_scan) {
+ assert(!has_partial_array_mask(ref_to_scan), "NarrowOop* elements should never be partial arrays.");
+ do_oop_evac(ref_to_scan);
+}
+
inline void G1ParScanThreadState::dispatch_reference(StarTask ref) {
assert(verify_task(ref), "sanity");
if (ref.is_narrow()) {
--- a/src/hotspot/share/gc/g1/g1Policy.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1Policy.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -383,10 +383,6 @@
bool adaptive_young_list_length() const;
- bool should_process_references() const {
- return true;
- }
-
void transfer_survivors_to_cset(const G1SurvivorRegions* survivors);
private:
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "gc/g1/dirtyCardQueue.hpp"
+#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1BlockOffsetTable.inline.hpp"
#include "gc/g1/g1CardTable.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
@@ -488,7 +489,7 @@
}
void G1RemSet::prepare_for_oops_into_collection_set_do() {
- DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
dcqs.concatenate_logs();
_scan_state->reset();
@@ -641,7 +642,7 @@
MutexLockerEx x(Shared_DirtyCardQ_lock,
Mutex::_no_safepoint_check_flag);
DirtyCardQueue* sdcq =
- JavaThread::dirty_card_queue_set().shared_dirty_card_queue();
+ G1BarrierSet::dirty_card_queue_set().shared_dirty_card_queue();
sdcq->enqueue(card_ptr);
}
} else {
--- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -53,7 +53,7 @@
void G1RemSetSummary::update() {
_num_conc_refined_cards = _rem_set->num_conc_refined_cards();
- DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
+ DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
_num_processed_buf_mutator = dcqs.processed_buffers_mut();
_num_processed_buf_rs_threads = dcqs.processed_buffers_rs_thread();
--- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -29,6 +29,7 @@
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/g1/bufferingOopClosure.hpp"
+#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CodeBlobClosure.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorState.hpp"
@@ -134,7 +135,7 @@
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SATBFiltering, worker_i);
if (!_process_strong_tasks.is_task_claimed(G1RP_PS_filter_satb_buffers) && _g1h->collector_state()->mark_or_rebuild_in_progress()) {
- JavaThread::satb_mark_queue_set().filter_thread_buffers();
+ G1BarrierSet::satb_mark_queue_set().filter_thread_buffers();
}
}
--- a/src/hotspot/share/gc/g1/g1StringDedup.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1StringDedup.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* 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 @@
#include "gc/g1/g1StringDedupStat.hpp"
#include "gc/g1/g1StringDedupTable.hpp"
#include "gc/g1/g1StringDedupThread.hpp"
+#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
bool G1StringDedup::_enabled = false;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/g1/g1ThreadLocalData.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_G1_G1THREADLOCALDATA_HPP
+#define SHARE_GC_G1_G1THREADLOCALDATA_HPP
+
+#include "gc/g1/dirtyCardQueue.hpp"
+#include "gc/g1/g1BarrierSet.hpp"
+#include "gc/g1/satbMarkQueue.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/sizes.hpp"
+
+class G1ThreadLocalData {
+private:
+ SATBMarkQueue _satb_mark_queue;
+ DirtyCardQueue _dirty_card_queue;
+
+ G1ThreadLocalData() :
+ _satb_mark_queue(&G1BarrierSet::satb_mark_queue_set()),
+ _dirty_card_queue(&G1BarrierSet::dirty_card_queue_set()) {}
+
+ static G1ThreadLocalData* data(Thread* thread) {
+ assert(UseG1GC, "Sanity");
+ return thread->gc_data<G1ThreadLocalData>();
+ }
+
+ static ByteSize satb_mark_queue_offset() {
+ return Thread::gc_data_offset() + byte_offset_of(G1ThreadLocalData, _satb_mark_queue);
+ }
+
+ static ByteSize dirty_card_queue_offset() {
+ return Thread::gc_data_offset() + byte_offset_of(G1ThreadLocalData, _dirty_card_queue);
+ }
+
+public:
+ static void create(Thread* thread) {
+ new (data(thread)) G1ThreadLocalData();
+ }
+
+ static void destroy(Thread* thread) {
+ data(thread)->~G1ThreadLocalData();
+ }
+
+ static SATBMarkQueue& satb_mark_queue(Thread* thread) {
+ return data(thread)->_satb_mark_queue;
+ }
+
+ static DirtyCardQueue& dirty_card_queue(Thread* thread) {
+ return data(thread)->_dirty_card_queue;
+ }
+
+ static ByteSize satb_mark_queue_active_offset() {
+ return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active();
+ }
+
+ static ByteSize satb_mark_queue_index_offset() {
+ return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index();
+ }
+
+ static ByteSize satb_mark_queue_buffer_offset() {
+ return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_buf();
+ }
+
+ static ByteSize dirty_card_queue_index_offset() {
+ return dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_index();
+ }
+
+ static ByteSize dirty_card_queue_buffer_offset() {
+ return dirty_card_queue_offset() + DirtyCardQueue::byte_offset_of_buf();
+ }
+};
+
+#endif // SHARE_GC_G1_G1THREADLOCALDATA_HPP
--- a/src/hotspot/share/gc/g1/g1_globals.cpp Tue Apr 17 08:54:17 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * 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.
- *
- */
-
-#include "precompiled.hpp"
-#include "gc/g1/g1_globals.hpp"
-
-G1_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
- MATERIALIZE_PD_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, \
- MATERIALIZE_PD_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, \
- MATERIALIZE_PD_DIAGNOSTIC_FLAG, \
- MATERIALIZE_EXPERIMENTAL_FLAG, \
- MATERIALIZE_NOTPRODUCT_FLAG, \
- MATERIALIZE_MANAGEABLE_FLAG, \
- MATERIALIZE_PRODUCT_RW_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
--- a/src/hotspot/share/gc/g1/g1_globals.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1_globals.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,25 +25,25 @@
#ifndef SHARE_VM_GC_G1_G1_GLOBALS_HPP
#define SHARE_VM_GC_G1_G1_GLOBALS_HPP
-#include "runtime/globals.hpp"
#include <float.h> // for DBL_MAX
//
// Defines all globals flags used by the garbage-first compiler.
//
-#define G1_FLAGS(develop, \
- develop_pd, \
- product, \
- product_pd, \
- diagnostic, \
- diagnostic_pd, \
- experimental, \
- notproduct, \
- manageable, \
- product_rw, \
- range, \
- constraint, \
- writeable) \
+#define GC_G1_FLAGS(develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
\
product(bool, G1UseAdaptiveIHOP, true, \
"Adaptively adjust the initiating heap occupancy from the " \
@@ -303,18 +303,4 @@
develop(bool, G1VerifyBitmaps, false, \
"Verifies the consistency of the marking bitmaps")
-G1_FLAGS(DECLARE_DEVELOPER_FLAG, \
- DECLARE_PD_DEVELOPER_FLAG, \
- DECLARE_PRODUCT_FLAG, \
- DECLARE_PD_PRODUCT_FLAG, \
- DECLARE_DIAGNOSTIC_FLAG, \
- DECLARE_PD_DIAGNOSTIC_FLAG, \
- DECLARE_EXPERIMENTAL_FLAG, \
- DECLARE_NOTPRODUCT_FLAG, \
- DECLARE_MANAGEABLE_FLAG, \
- DECLARE_PRODUCT_RW_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-
#endif // SHARE_VM_GC_G1_G1_GLOBALS_HPP
--- a/src/hotspot/share/gc/g1/heapRegionSet.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/heapRegionSet.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -26,6 +26,7 @@
#define SHARE_VM_GC_G1_HEAPREGIONSET_HPP
#include "gc/g1/heapRegion.hpp"
+#include "utilities/macros.hpp"
#define assert_heap_region_set(p, message) \
do { \
@@ -46,13 +47,6 @@
} while (0)
-// Set verification will be forced either if someone defines
-// HEAP_REGION_SET_FORCE_VERIFY to be 1, or in builds in which
-// asserts are compiled in.
-#ifndef HEAP_REGION_SET_FORCE_VERIFY
-#define HEAP_REGION_SET_FORCE_VERIFY defined(ASSERT)
-#endif // HEAP_REGION_SET_FORCE_VERIFY
-
class HRSMtSafeChecker : public CHeapObj<mtGC> {
public:
virtual void check() = 0;
@@ -122,13 +116,7 @@
void verify_next_region(HeapRegion* hr);
void verify_end();
-#if HEAP_REGION_SET_FORCE_VERIFY
- void verify_optional() {
- verify();
- }
-#else // HEAP_REGION_SET_FORCE_VERIFY
- void verify_optional() { }
-#endif // HEAP_REGION_SET_FORCE_VERIFY
+ void verify_optional() { DEBUG_ONLY(verify();) }
virtual void print_on(outputStream* out, bool print_contents = false);
};
--- a/src/hotspot/share/gc/g1/satbMarkQueue.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/satbMarkQueue.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "jvm.h"
#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#include "gc/g1/satbMarkQueue.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "memory/allocation.inline.hpp"
@@ -103,7 +104,7 @@
}
inline bool retain_entry(const void* entry, G1CollectedHeap* heap) {
- return requires_marking(entry, heap) && !heap->isMarkedNext((oop)entry);
+ return requires_marking(entry, heap) && !heap->is_marked_next((oop)entry);
}
// This method removes entries from a SATB buffer that will not be
@@ -207,7 +208,7 @@
}
void SATBMarkQueueSet::handle_zero_index_for_thread(JavaThread* t) {
- t->satb_mark_queue().handle_zero_index();
+ G1ThreadLocalData::satb_mark_queue(t).handle_zero_index();
}
#ifdef ASSERT
@@ -216,7 +217,7 @@
log_error(gc, verify)("Actual SATB active states:");
log_error(gc, verify)(" Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE");
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
- log_error(gc, verify)(" Thread \"%s\" queue: %s", t->name(), t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE");
+ log_error(gc, verify)(" Thread \"%s\" queue: %s", t->name(), G1ThreadLocalData::satb_mark_queue(t).is_active() ? "ACTIVE" : "INACTIVE");
}
log_error(gc, verify)(" Shared queue: %s", shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE");
}
@@ -230,7 +231,7 @@
// Verify thread queue states
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
- if (t->satb_mark_queue().is_active() != expected_active) {
+ if (G1ThreadLocalData::satb_mark_queue(t).is_active() != expected_active) {
dump_active_states(expected_active);
guarantee(false, "Thread SATB queue has an unexpected active state");
}
@@ -251,14 +252,14 @@
#endif // ASSERT
_all_active = active;
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
- t->satb_mark_queue().set_active(active);
+ G1ThreadLocalData::satb_mark_queue(t).set_active(active);
}
shared_satb_queue()->set_active(active);
}
void SATBMarkQueueSet::filter_thread_buffers() {
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
- t->satb_mark_queue().filter();
+ G1ThreadLocalData::satb_mark_queue(t).filter();
}
shared_satb_queue()->filter();
}
@@ -312,7 +313,7 @@
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
jio_snprintf(buffer, SATB_PRINTER_BUFFER_SIZE, "Thread: %s", t->name());
- t->satb_mark_queue().print(buffer);
+ G1ThreadLocalData::satb_mark_queue(t).print(buffer);
}
shared_satb_queue()->print("Shared");
@@ -343,7 +344,7 @@
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
// So we can safely manipulate these queues.
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) {
- t->satb_mark_queue().reset();
+ G1ThreadLocalData::satb_mark_queue(t).reset();
}
shared_satb_queue()->reset();
}
--- a/src/hotspot/share/gc/g1/vmStructs_g1.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/g1/vmStructs_g1.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,7 +30,9 @@
#include "gc/g1/heapRegionManager.hpp"
#include "utilities/macros.hpp"
-#define VM_STRUCTS_G1(nonstatic_field, static_field) \
+#define VM_STRUCTS_G1GC(nonstatic_field, \
+ volatile_nonstatic_field, \
+ static_field) \
\
static_field(HeapRegion, GrainBytes, size_t) \
static_field(HeapRegion, LogOfHRGrainBytes, int) \
@@ -67,10 +69,9 @@
\
nonstatic_field(PtrQueue, _active, bool) \
nonstatic_field(PtrQueue, _buf, void**) \
- nonstatic_field(PtrQueue, _index, size_t) \
+ nonstatic_field(PtrQueue, _index, size_t)
-
-#define VM_INT_CONSTANTS_G1(declare_constant, declare_constant_with_value) \
+#define VM_INT_CONSTANTS_G1GC(declare_constant, declare_constant_with_value) \
declare_constant(HeapRegionType::FreeTag) \
declare_constant(HeapRegionType::YoungMask) \
declare_constant(HeapRegionType::EdenTag) \
@@ -80,12 +81,13 @@
declare_constant(HeapRegionType::ArchiveMask) \
declare_constant(HeapRegionType::StartsHumongousTag) \
declare_constant(HeapRegionType::ContinuesHumongousTag) \
- declare_constant(HeapRegionType::OldMask)
-
+ declare_constant(HeapRegionType::OldMask) \
+ declare_constant(BarrierSet::G1BarrierSet) \
+ declare_constant(G1CardTable::g1_young_gen)
-#define VM_TYPES_G1(declare_type, \
- declare_toplevel_type, \
- declare_integer_type) \
+#define VM_TYPES_G1GC(declare_type, \
+ declare_toplevel_type, \
+ declare_integer_type) \
\
declare_toplevel_type(G1HeapRegionTable) \
\
@@ -98,6 +100,8 @@
declare_toplevel_type(G1MonitoringSupport) \
declare_toplevel_type(PtrQueue) \
declare_toplevel_type(HeapRegionType) \
+ declare_toplevel_type(SATBMarkQueue) \
+ declare_toplevel_type(DirtyCardQueue) \
\
declare_toplevel_type(G1CollectedHeap*) \
declare_toplevel_type(HeapRegion*) \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 "runtime/commandLineFlagRangeList.hpp"
+#include "runtime/globals.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+Flag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose) {
+ // Parallel GC passes ParallelGCThreads when creating GrowableArray as 'int' type parameter.
+ // So can't exceed with "max_jint"
+
+ if (UseParallelGC && (value > (uint)max_jint)) {
+ CommandLineError::print(verbose,
+ "ParallelGCThreads (" UINT32_FORMAT ") must be "
+ "less than or equal to " UINT32_FORMAT " for Parallel GC\n",
+ value, max_jint);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) {
+ // InitialTenuringThreshold is only used for ParallelGC.
+ if (UseParallelGC && (value > MaxTenuringThreshold)) {
+ CommandLineError::print(verbose,
+ "InitialTenuringThreshold (" UINTX_FORMAT ") must be "
+ "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n",
+ value, MaxTenuringThreshold);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose) {
+ // As only ParallelGC uses InitialTenuringThreshold,
+ // we don't need to compare InitialTenuringThreshold with MaxTenuringThreshold.
+ if (UseParallelGC && (value < InitialTenuringThreshold)) {
+ CommandLineError::print(verbose,
+ "MaxTenuringThreshold (" UINTX_FORMAT ") must be "
+ "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n",
+ value, InitialTenuringThreshold);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+
+ return Flag::SUCCESS;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/commandLineFlagConstraintsParallel.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,36 @@
+/*
+ * 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
+ * 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_GC_PARALLEL_COMMANDLINEFLAGCONSTRAINTSPARALLEL_HPP
+#define SHARE_GC_PARALLEL_COMMANDLINEFLAGCONSTRAINTSPARALLEL_HPP
+
+#include "runtime/globals.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+// Parallel Subconstraints
+Flag::Error ParallelGCThreadsConstraintFuncParallel(uint value, bool verbose);
+Flag::Error InitialTenuringThresholdConstraintFuncParallel(uintx value, bool verbose);
+Flag::Error MaxTenuringThresholdConstraintFuncParallel(uintx value, bool verbose);
+
+#endif // SHARE_GC_PARALLEL_COMMANDLINEFLAGCONSTRAINTSPARALLEL_HPP
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -73,7 +73,7 @@
card_table->initialize();
CardTableBarrierSet* const barrier_set = new CardTableBarrierSet(card_table);
barrier_set->initialize();
- set_barrier_set(barrier_set);
+ BarrierSet::set_barrier_set(barrier_set);
// Make up the generations
// Calculate the maximum size that a generation can grow. This
@@ -627,7 +627,7 @@
}
CardTableBarrierSet* ParallelScavengeHeap::barrier_set() {
- return barrier_set_cast<CardTableBarrierSet>(CollectedHeap::barrier_set());
+ return barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
}
PSCardTable* ParallelScavengeHeap::card_table() {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/parallel_globals.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_PARALLEL_PARALLEL_GLOBALS_HPP
+#define SHARE_GC_PARALLEL_PARALLEL_GLOBALS_HPP
+
+#define GC_PARALLEL_FLAGS(develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+ product(uintx, HeapMaximumCompactionInterval, 20, \
+ "How often should we maximally compact the heap (not allowing " \
+ "any dead space)") \
+ range(0, max_uintx) \
+ \
+ product(uintx, HeapFirstMaximumCompactionCount, 3, \
+ "The collection count for the first maximum compaction") \
+ range(0, max_uintx) \
+ \
+ product(bool, UseMaximumCompactionOnSystemGC, true, \
+ "Use maximum compaction in the Parallel Old garbage collector " \
+ "for a system GC") \
+ \
+ product(uintx, ParallelOldDeadWoodLimiterMean, 50, \
+ "The mean used by the parallel compact dead wood " \
+ "limiter (a number between 0-100)") \
+ range(0, 100) \
+ \
+ product(uintx, ParallelOldDeadWoodLimiterStdDev, 80, \
+ "The standard deviation used by the parallel compact dead wood " \
+ "limiter (a number between 0-100)") \
+ range(0, 100) \
+ \
+ develop(bool, TraceGCTaskManager, false, \
+ "Trace actions of the GC task manager") \
+ \
+ develop(bool, TraceGCTaskQueue, false, \
+ "Trace actions of the GC task queues") \
+ \
+ develop(bool, TraceParallelOldGCMarkingPhase, false, \
+ "Trace marking phase in ParallelOldGC") \
+ \
+ develop(bool, TraceParallelOldGCDensePrefix, false, \
+ "Trace dense prefix computation for ParallelOldGC") \
+ \
+ develop(uintx, GCWorkerDelayMillis, 0, \
+ "Delay in scheduling GC workers (in milliseconds)") \
+ \
+ product(bool, PSChunkLargeArrays, true, \
+ "Process large arrays in chunks")
+
+#endif // SHARE_GC_PARALLEL_PARALLEL_GLOBALS_HPP
--- a/src/hotspot/share/gc/parallel/psMarkSweepDecorator.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psMarkSweepDecorator.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -112,8 +112,8 @@
const intx interval = PrefetchScanIntervalInBytes;
while (q < t) {
- assert(oop(q)->mark()->is_marked() || oop(q)->mark()->is_unlocked() ||
- oop(q)->mark()->has_bias_pattern(),
+ assert(oop(q)->mark_raw()->is_marked() || oop(q)->mark_raw()->is_unlocked() ||
+ oop(q)->mark_raw()->has_bias_pattern(),
"these are the only valid states during a mark sweep");
if (oop(q)->is_gc_marked()) {
/* prefetch beyond q */
@@ -150,7 +150,7 @@
} else {
// if the object isn't moving we can just set the mark to the default
// mark and handle it specially later on.
- oop(q)->init_mark();
+ oop(q)->init_mark_raw();
assert(oop(q)->forwardee() == NULL, "should be forwarded to NULL");
}
@@ -210,7 +210,7 @@
} else {
// if the object isn't moving we can just set the mark to the default
// mark and handle it specially later on.
- oop(q)->init_mark();
+ oop(q)->init_mark_raw();
assert(oop(q)->forwardee() == NULL, "should be forwarded to NULL");
}
@@ -258,7 +258,7 @@
if (allowed_deadspace_words >= deadlength) {
allowed_deadspace_words -= deadlength;
CollectedHeap::fill_with_object(q, deadlength);
- oop(q)->set_mark(oop(q)->mark()->set_marked());
+ oop(q)->set_mark_raw(oop(q)->mark_raw()->set_marked());
assert((int) deadlength == oop(q)->size(), "bad filler object size");
// Recall that we required "q == compaction_top".
return true;
@@ -349,7 +349,7 @@
q = t;
} else {
// $$$ Funky
- q = (HeapWord*) oop(_first_dead)->mark()->decode_pointer();
+ q = (HeapWord*) oop(_first_dead)->mark_raw()->decode_pointer();
}
}
@@ -360,7 +360,7 @@
if (!oop(q)->is_gc_marked()) {
// mark is pointer to next marked oop
debug_only(prev_q = q);
- q = (HeapWord*) oop(q)->mark()->decode_pointer();
+ q = (HeapWord*) oop(q)->mark_raw()->decode_pointer();
assert(q > prev_q, "we should be moving forward through memory");
} else {
// prefetch beyond q
@@ -376,7 +376,7 @@
// copy object and reinit its mark
assert(q != compaction_top, "everything in this pass should be moving");
Copy::aligned_conjoint_words(q, compaction_top, size);
- oop(compaction_top)->init_mark();
+ oop(compaction_top)->init_mark_raw();
assert(oop(compaction_top)->klass() != NULL, "should have a class");
debug_only(prev_q = q);
--- a/src/hotspot/share/gc/parallel/psPromotionLAB.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psPromotionLAB.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -82,7 +82,7 @@
// so they can always fill with an array.
HeapWord* tlab_end = end() + filler_header_size;
typeArrayOop filler_oop = (typeArrayOop) top();
- filler_oop->set_mark(markOopDesc::prototype());
+ filler_oop->set_mark_raw(markOopDesc::prototype());
filler_oop->set_klass(Universe::intArrayKlassObj());
const size_t array_length =
pointer_delta(tlab_end, top()) - typeArrayOopDesc::header_size(T_INT);
--- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -116,7 +116,7 @@
// NOTE! We must be very careful with any methods that access the mark
// in o. There may be multiple threads racing on it, and it may be forwarded
// at any time. Do not use oop methods for accessing the mark!
- markOop test_mark = o->mark();
+ markOop test_mark = o->mark_raw();
// The same test as "o->is_forwarded()"
if (!test_mark->is_marked()) {
--- a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psScavenge.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -32,6 +32,7 @@
#include "memory/iterator.hpp"
#include "memory/resourceArea.hpp"
#include "oops/access.inline.hpp"
+#include "oops/oop.inline.hpp"
#include "utilities/globalDefinitions.hpp"
inline void PSScavenge::save_to_space_top_before_gc() {
--- a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,6 +25,16 @@
#ifndef SHARE_VM_GC_PARALLEL_VMSTRUCTS_PARALLELGC_HPP
#define SHARE_VM_GC_PARALLEL_VMSTRUCTS_PARALLELGC_HPP
+#include "gc/parallel/asPSOldGen.hpp"
+#include "gc/parallel/asPSYoungGen.hpp"
+#include "gc/parallel/immutableSpace.hpp"
+#include "gc/parallel/mutableSpace.hpp"
+#include "gc/parallel/parallelScavengeHeap.hpp"
+#include "gc/parallel/psOldGen.hpp"
+#include "gc/parallel/psVirtualspace.hpp"
+#include "gc/parallel/psYoungGen.hpp"
+#include "gc/parallel/vmStructs_parallelgc.hpp"
+
#define VM_STRUCTS_PARALLELGC(nonstatic_field, \
volatile_nonstatic_field, \
static_field) \
@@ -65,7 +75,9 @@
\
#define VM_TYPES_PARALLELGC(declare_type, \
- declare_toplevel_type) \
+ declare_toplevel_type, \
+ declare_integer_type) \
+ \
\
/*****************************************/ \
/* Parallel GC - space, gen abstractions */ \
@@ -93,4 +105,7 @@
declare_toplevel_type(ASPSOldGen*) \
declare_toplevel_type(ParallelScavengeHeap*)
+#define VM_INT_CONSTANTS_PARALLELGC(declare_constant, \
+ declare_constant_with_value)
+
#endif // SHARE_VM_GC_PARALLEL_VMSTRUCTS_PARALLELGC_HPP
--- a/src/hotspot/share/gc/serial/defNewGeneration.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -174,9 +174,6 @@
void ScanWeakRefClosure::do_oop(oop* p) { ScanWeakRefClosure::do_oop_work(p); }
void ScanWeakRefClosure::do_oop(narrowOop* p) { ScanWeakRefClosure::do_oop_work(p); }
-void FilteringClosure::do_oop(oop* p) { FilteringClosure::do_oop_work(p); }
-void FilteringClosure::do_oop(narrowOop* p) { FilteringClosure::do_oop_work(p); }
-
DefNewGeneration::DefNewGeneration(ReservedSpace rs,
size_t initial_size,
const char* policy)
@@ -753,7 +750,7 @@
_promotion_failed = true;
_promotion_failed_info.register_copy_failure(old->size());
- _preserved_marks_set.get()->push_if_necessary(old, old->mark());
+ _preserved_marks_set.get()->push_if_necessary(old, old->mark_raw());
// forward to self
old->forward_to(old);
@@ -1009,9 +1006,11 @@
// have to use it here, as well.
HeapWord* result = eden()->par_allocate(word_size);
if (result != NULL) {
+#if INCLUDE_ALL_GCS
if (CMSEdenChunksRecordAlways && _old_gen != NULL) {
_old_gen->sample_eden_chunk();
}
+#endif
} else {
// If the eden is full and the last collection bailed out, we are running
// out of heap space, and we try to allocate the from-space, too.
@@ -1025,9 +1024,11 @@
HeapWord* DefNewGeneration::par_allocate(size_t word_size,
bool is_tlab) {
HeapWord* res = eden()->par_allocate(word_size);
+#if INCLUDE_ALL_GCS
if (CMSEdenChunksRecordAlways && _old_gen != NULL) {
_old_gen->sample_eden_chunk();
}
+#endif
return res;
}
--- a/src/hotspot/share/gc/serial/markSweep.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/serial/markSweep.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* 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 @@
#include "precompiled.hpp"
#include "compiler/compileBroker.hpp"
#include "gc/serial/markSweep.inline.hpp"
+#include "gc/serial/serial_specialized_oop_closures.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "gc/shared/gcTimer.hpp"
#include "gc/shared/gcTrace.hpp"
-#include "gc/shared/specialized_oop_closures.hpp"
#include "memory/iterator.inline.hpp"
#include "oops/access.inline.hpp"
#include "oops/compressedOops.inline.hpp"
@@ -66,8 +66,8 @@
inline void MarkSweep::mark_object(oop obj) {
// some marks may contain information we need to preserve so we store them away
// and overwrite the mark. We'll restore it at the end of markSweep.
- markOop mark = obj->mark();
- obj->set_mark(markOopDesc::prototype()->set_marked());
+ markOop mark = obj->mark_raw();
+ obj->set_mark_raw(markOopDesc::prototype()->set_marked());
if (mark->must_be_preserved(obj)) {
preserve_mark(obj, mark);
@@ -78,7 +78,7 @@
T heap_oop = RawAccess<>::oop_load(p);
if (!CompressedOops::is_null(heap_oop)) {
oop obj = CompressedOops::decode_not_null(heap_oop);
- if (!obj->mark()->is_marked()) {
+ if (!obj->mark_raw()->is_marked()) {
mark_object(obj);
_marking_stack.push(obj);
}
@@ -174,7 +174,7 @@
T heap_oop = RawAccess<>::oop_load(p);
if (!CompressedOops::is_null(heap_oop)) {
oop obj = CompressedOops::decode_not_null(heap_oop);
- if (!obj->mark()->is_marked()) {
+ if (!obj->mark_raw()->is_marked()) {
mark_object(obj);
follow_object(obj);
}
@@ -190,7 +190,7 @@
}
void PreservedMark::restore() {
- _obj->set_mark(_mark);
+ _obj->set_mark_raw(_mark);
}
// We preserve the mark which should be replaced at the end and the location
@@ -252,7 +252,7 @@
while (!_preserved_oop_stack.is_empty()) {
oop obj = _preserved_oop_stack.pop();
markOop mark = _preserved_mark_stack.pop();
- obj->set_mark(mark);
+ obj->set_mark_raw(mark);
}
}
--- a/src/hotspot/share/gc/serial/markSweep.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/serial/markSweep.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,11 +43,11 @@
oop obj = CompressedOops::decode_not_null(heap_oop);
assert(Universe::heap()->is_in(obj), "should be in heap");
- oop new_obj = oop(obj->mark()->decode_pointer());
+ oop new_obj = oop(obj->mark_raw()->decode_pointer());
assert(new_obj != NULL || // is forwarding ptr?
- obj->mark() == markOopDesc::prototype() || // not gc marked?
- (UseBiasedLocking && obj->mark()->has_bias_pattern()),
+ obj->mark_raw() == markOopDesc::prototype() || // not gc marked?
+ (UseBiasedLocking && obj->mark_raw()->has_bias_pattern()),
// not gc marked?
"should be forwarded");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/serial/serial_globals.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_SERIAL_SERIAL_GLOBALS_HPP
+#define SHARE_GC_SERIAL_SERIAL_GLOBALS_HPP
+
+#define GC_SERIAL_FLAGS(develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable)
+
+#endif // SHARE_GC_SERIAL_SERIAL_GLOBALS_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/serial/serial_specialized_oop_closures.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_SERIAL_SERIAL_SPECIALIZED_OOP_CLOSURES_HPP
+#define SHARE_GC_SERIAL_SERIAL_SPECIALIZED_OOP_CLOSURES_HPP
+
+// The following OopClosure types get specialized versions of
+// "oop_oop_iterate" that invoke the closures' do_oop methods
+// non-virtually, using a mechanism defined in this file. Extend these
+// macros in the obvious way to add specializations for new closures.
+
+// Forward declarations.
+
+// DefNew
+class ScanClosure;
+class FastScanClosure;
+class FilteringClosure;
+
+// MarkSweep
+class MarkAndPushClosure;
+class AdjustPointerClosure;
+
+#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(f) \
+ f(ScanClosure,_nv) \
+ f(FastScanClosure,_nv) \
+ f(FilteringClosure,_nv)
+
+#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_MS(f) \
+ f(MarkAndPushClosure,_nv) \
+ f(AdjustPointerClosure,_nv)
+
+#define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_S(f) \
+ f(ScanClosure,_nv) \
+ f(FastScanClosure,_nv)
+
+#endif // SHARE_GC_SERIAL_SERIAL_SPECIALIZED_OOP_CLOSURES_HPP
--- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,6 +30,7 @@
#include "gc/shared/collectorCounters.hpp"
#include "gc/shared/gcTimer.hpp"
#include "gc/shared/gcTrace.hpp"
+#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/genOopClosures.inline.hpp"
#include "gc/shared/generationSpec.hpp"
#include "gc/shared/space.hpp"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/serial/vmStructs_serial.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_SERIAL_VMSTRUCTS_HPP
+#define SHARE_GC_SERIAL_VMSTRUCTS_HPP
+
+#include "gc/serial/serialHeap.hpp"
+#include "gc/serial/tenuredGeneration.hpp"
+
+#define VM_STRUCTS_SERIALGC(nonstatic_field, \
+ volatile_nonstatic_field, \
+ static_field) \
+ nonstatic_field(TenuredGeneration, _min_heap_delta_bytes, size_t) \
+ nonstatic_field(TenuredGeneration, _the_space, ContiguousSpace*)
+
+#define VM_TYPES_SERIALGC(declare_type, \
+ declare_toplevel_type, \
+ declare_integer_type) \
+ declare_type(SerialHeap, GenCollectedHeap) \
+ declare_type(TenuredGeneration, CardGeneration) \
+ declare_type(TenuredSpace, OffsetTableContigSpace) \
+ \
+ declare_toplevel_type(TenuredGeneration*)
+
+#define VM_INT_CONSTANTS_SERIALGC(declare_constant, \
+ declare_constant_with_value)
+
+#endif // SHARE_GC_SERIAL_VMSTRUCTS_SERIAL_HPP
--- a/src/hotspot/share/gc/shared/barrierSet.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/barrierSet.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -24,5 +24,27 @@
#include "precompiled.hpp"
#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/macros.hpp"
-BarrierSet* BarrierSet::_bs = NULL;
+BarrierSet* BarrierSet::_barrier_set = NULL;
+
+void BarrierSet::set_barrier_set(BarrierSet* barrier_set) {
+ assert(_barrier_set == NULL, "Already initialized");
+ _barrier_set = barrier_set;
+
+ // The barrier set was not initialized when the this thread (the main thread)
+ // was created, so the call to BarrierSet::on_thread_create() had to be deferred
+ // until we have a barrier set. Now we have a barrier set, so we make the call.
+ _barrier_set->on_thread_create(Thread::current());
+}
+
+// Called from init.cpp
+void gc_barrier_stubs_init() {
+ BarrierSet* bs = BarrierSet::barrier_set();
+#ifndef ZERO
+ BarrierSetAssembler* bs_assembler = bs->barrier_set_assembler();
+ bs_assembler->barrier_stubs_init();
+#endif
+}
--- a/src/hotspot/share/gc/shared/barrierSet.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/barrierSet.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -42,7 +42,7 @@
class BarrierSet: public CHeapObj<mtGC> {
friend class VMStructs;
- static BarrierSet* _bs;
+ static BarrierSet* _barrier_set;
public:
enum Name {
@@ -52,8 +52,6 @@
UnknownBS
};
- static BarrierSet* barrier_set() { return _bs; }
-
protected:
// Fake RTTI support. For a derived class T to participate
// - T must have a corresponding Name entry.
@@ -107,6 +105,8 @@
// is redone until it succeeds. This can e.g. prevent allocations from the slow path
// to be in old.
virtual void on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) {}
+ virtual void on_thread_create(Thread* thread) {}
+ virtual void on_thread_destroy(Thread* thread) {}
virtual void on_thread_attach(JavaThread* thread) {}
virtual void on_thread_detach(JavaThread* thread) {}
virtual void make_parsable(JavaThread* thread) {}
@@ -115,7 +115,8 @@
// Print a description of the memory for the barrier set
virtual void print_on(outputStream* st) const = 0;
- static void set_bs(BarrierSet* bs) { _bs = bs; }
+ static BarrierSet* barrier_set() { return _barrier_set; }
+ static void set_barrier_set(BarrierSet* barrier_set);
BarrierSetAssembler* barrier_set_assembler() {
assert(_barrier_set_assembler != NULL, "should be set");
--- a/src/hotspot/share/gc/shared/cardGeneration.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/cardGeneration.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,6 +28,7 @@
#include "gc/shared/cardGeneration.inline.hpp"
#include "gc/shared/cardTableRS.hpp"
#include "gc/shared/gcLocker.hpp"
+#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/genOopClosures.inline.hpp"
#include "gc/shared/generationSpec.hpp"
#include "gc/shared/space.inline.hpp"
--- a/src/hotspot/share/gc/shared/cardGeneration.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/cardGeneration.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -31,6 +31,7 @@
#include "gc/shared/generation.hpp"
class BlockOffsetSharedArray;
+class CardTableRS;
class CompactibleSpace;
class CardGeneration: public Generation {
--- a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -26,7 +26,6 @@
#include "gc/shared/cardTableBarrierSetAssembler.hpp"
#include "gc/shared/cardTableBarrierSet.inline.hpp"
#include "gc/shared/collectedHeap.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/space.inline.hpp"
#include "logging/log.hpp"
#include "memory/virtualspace.hpp"
--- a/src/hotspot/share/gc/shared/cardTableRS.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/cardTableRS.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -279,36 +279,24 @@
void CardTableRS::younger_refs_in_space_iterate(Space* sp,
OopsInGenClosure* cl,
uint n_threads) {
+ verify_used_region_at_save_marks(sp);
+
const MemRegion urasm = sp->used_region_at_save_marks();
+ non_clean_card_iterate_possibly_parallel(sp, urasm, cl, this, n_threads);
+}
+
#ifdef ASSERT
- // Convert the assertion check to a warning if we are running
- // CMS+ParNew until related bug is fixed.
+void CardTableRS::verify_used_region_at_save_marks(Space* sp) const {
MemRegion ur = sp->used_region();
- assert(ur.contains(urasm) || (UseConcMarkSweepGC),
+ MemRegion urasm = sp->used_region_at_save_marks();
+
+ assert(ur.contains(urasm),
"Did you forget to call save_marks()? "
"[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in "
"[" PTR_FORMAT ", " PTR_FORMAT ")",
p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end()));
- // In the case of CMS+ParNew, issue a warning
- if (!ur.contains(urasm)) {
- assert(UseConcMarkSweepGC, "Tautology: see assert above");
- log_warning(gc)("CMS+ParNew: Did you forget to call save_marks()? "
- "[" PTR_FORMAT ", " PTR_FORMAT ") is not contained in "
- "[" PTR_FORMAT ", " PTR_FORMAT ")",
- p2i(urasm.start()), p2i(urasm.end()), p2i(ur.start()), p2i(ur.end()));
- MemRegion ur2 = sp->used_region();
- MemRegion urasm2 = sp->used_region_at_save_marks();
- if (!ur.equals(ur2)) {
- log_warning(gc)("CMS+ParNew: Flickering used_region()!!");
- }
- if (!urasm.equals(urasm2)) {
- log_warning(gc)("CMS+ParNew: Flickering used_region_at_save_marks()!!");
- }
- ShouldNotReachHere();
- }
+}
#endif
- non_clean_card_iterate_possibly_parallel(sp, urasm, cl, this, n_threads);
-}
void CardTableRS::clear_into_younger(Generation* old_gen) {
assert(GenCollectedHeap::heap()->is_old_gen(old_gen),
@@ -611,8 +599,8 @@
CardTable::verify();
}
-CardTableRS::CardTableRS(MemRegion whole_heap) :
- CardTable(whole_heap, /* scanned concurrently */ UseConcMarkSweepGC && CMSPrecleaningEnabled),
+CardTableRS::CardTableRS(MemRegion whole_heap, bool scanned_concurrently) :
+ CardTable(whole_heap, scanned_concurrently),
_cur_youngergen_card_val(youngergenP1_card),
// LNC functionality
_lowest_non_clean(NULL),
@@ -698,11 +686,7 @@
{
if (!mr.is_empty()) {
if (n_threads > 0) {
-#if INCLUDE_ALL_GCS
non_clean_card_iterate_parallel_work(sp, mr, cl, ct, n_threads);
-#else // INCLUDE_ALL_GCS
- fatal("Parallel gc not supported here.");
-#endif // INCLUDE_ALL_GCS
} else {
// clear_cl finds contiguous dirty ranges of cards to process and clear.
@@ -717,6 +701,12 @@
}
}
+void CardTableRS::non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
+ OopsInGenClosure* cl, CardTableRS* ct,
+ uint n_threads) {
+ fatal("Parallel gc not supported here.");
+}
+
bool CardTableRS::is_in_young(oop obj) const {
return GenCollectedHeap::heap()->is_in_young(obj);
}
--- a/src/hotspot/share/gc/shared/cardTableRS.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/cardTableRS.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -99,13 +99,15 @@
jbyte find_unused_youngergenP_card_value();
public:
- CardTableRS(MemRegion whole_heap);
+ CardTableRS(MemRegion whole_heap, bool scanned_concurrently);
~CardTableRS();
CLDRemSet* cld_rem_set() { return &_cld_rem_set; }
void younger_refs_in_space_iterate(Space* sp, OopsInGenClosure* cl, uint n_threads);
+ virtual void verify_used_region_at_save_marks(Space* sp) const NOT_DEBUG_RETURN;
+
// Override.
void prepare_for_younger_refs_iterate(bool parallel);
@@ -174,9 +176,9 @@
// Work method used to implement non_clean_card_iterate_possibly_parallel()
// above in the parallel case.
- void non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
- OopsInGenClosure* cl, CardTableRS* ct,
- uint n_threads);
+ virtual void non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
+ OopsInGenClosure* cl, CardTableRS* ct,
+ uint n_threads);
// This is an array, one element per covered region of the card table.
// Each entry is itself an array, with one element per chunk in the
@@ -190,53 +192,7 @@
uintptr_t* _lowest_non_clean_base_chunk_index;
volatile int* _last_LNC_resizing_collection;
- // Initializes "lowest_non_clean" to point to the array for the region
- // covering "sp", and "lowest_non_clean_base_chunk_index" to the chunk
- // index of the corresponding to the first element of that array.
- // Ensures that these arrays are of sufficient size, allocating if necessary.
- // May be called by several threads concurrently.
- void get_LNC_array_for_space(Space* sp,
- jbyte**& lowest_non_clean,
- uintptr_t& lowest_non_clean_base_chunk_index,
- size_t& lowest_non_clean_chunk_size);
-
- // Returns the number of chunks necessary to cover "mr".
- size_t chunks_to_cover(MemRegion mr) {
- return (size_t)(addr_to_chunk_index(mr.last()) -
- addr_to_chunk_index(mr.start()) + 1);
- }
-
- // Returns the index of the chunk in a stride which
- // covers the given address.
- uintptr_t addr_to_chunk_index(const void* addr) {
- uintptr_t card = (uintptr_t) byte_for(addr);
- return card / ParGCCardsPerStrideChunk;
- }
-
- // Apply cl, which must either itself apply dcto_cl or be dcto_cl,
- // to the cards in the stride (of n_strides) within the given space.
- void process_stride(Space* sp,
- MemRegion used,
- jint stride, int n_strides,
- OopsInGenClosure* cl,
- CardTableRS* ct,
- jbyte** lowest_non_clean,
- uintptr_t lowest_non_clean_base_chunk_index,
- size_t lowest_non_clean_chunk_size);
-
- // Makes sure that chunk boundaries are handled appropriately, by
- // adjusting the min_done of dcto_cl, and by using a special card-table
- // value to indicate how min_done should be set.
- void process_chunk_boundaries(Space* sp,
- DirtyCardToOopClosure* dcto_cl,
- MemRegion chunk_mr,
- MemRegion used,
- jbyte** lowest_non_clean,
- uintptr_t lowest_non_clean_base_chunk_index,
- size_t lowest_non_clean_chunk_size);
-
virtual bool is_in_young(oop obj) const;
-
};
class ClearNoncleanCardWrapper: public MemRegionClosure {
--- a/src/hotspot/share/gc/shared/collectedHeap.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/collectedHeap.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -137,7 +137,7 @@
print_extended_on(st);
st->cr();
- _barrier_set->print_on(st);
+ BarrierSet::barrier_set()->print_on(st);
}
void CollectedHeap::trace_heap(GCWhen::Type when, const GCTracer* gc_tracer) {
@@ -176,7 +176,6 @@
CollectedHeap::CollectedHeap() :
- _barrier_set(NULL),
_is_gc_active(false),
_total_collections(0),
_total_full_collections(0),
@@ -311,11 +310,6 @@
} while (true); // Until a GC is done
}
-void CollectedHeap::set_barrier_set(BarrierSet* barrier_set) {
- _barrier_set = barrier_set;
- BarrierSet::set_bs(barrier_set);
-}
-
#ifndef PRODUCT
void CollectedHeap::check_for_bad_heap_word_value(HeapWord* addr, size_t size) {
if (CheckMemoryInitialization && ZapUnusedHeapArea) {
@@ -522,7 +516,7 @@
assert(!use_tlab || jtiwh.length() > 0,
"Attempt to fill tlabs before main thread has been added"
" to threads list is doomed to failure!");
- BarrierSet *bs = barrier_set();
+ BarrierSet *bs = BarrierSet::barrier_set();
for (; JavaThread *thread = jtiwh.next(); ) {
if (use_tlab) thread->tlab().make_parsable(retire_tlabs);
bs->make_parsable(thread);
--- a/src/hotspot/share/gc/shared/collectedHeap.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/collectedHeap.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -105,7 +105,6 @@
MemRegion _reserved;
protected:
- BarrierSet* _barrier_set;
bool _is_gc_active;
// Used for filler objects (static, but initialized in ctor).
@@ -417,10 +416,6 @@
size_t size,
Metaspace::MetadataType mdtype);
- // Returns the barrier set for this heap
- BarrierSet* barrier_set() { return _barrier_set; }
- void set_barrier_set(BarrierSet* barrier_set);
-
// Returns "true" iff there is a stop-world GC in progress. (I assume
// that it should answer "false" for the concurrent part of a concurrent
// collector -- dld).
--- a/src/hotspot/share/gc/shared/collectedHeap.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/collectedHeap.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -61,10 +61,10 @@
assert(obj != NULL, "NULL object pointer");
if (UseBiasedLocking && (klass != NULL)) {
- obj->set_mark(klass->prototype_header());
+ obj->set_mark_raw(klass->prototype_header());
} else {
// May be bootstrapping
- obj->set_mark(markOopDesc::prototype());
+ obj->set_mark_raw(markOopDesc::prototype());
}
}
--- a/src/hotspot/share/gc/shared/collectorPolicy.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/collectorPolicy.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,7 +28,6 @@
#include "gc/shared/collectorPolicy.hpp"
#include "gc/shared/gcLocker.hpp"
#include "gc/shared/gcPolicyCounters.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/generationSpec.hpp"
#include "gc/shared/space.hpp"
#include "gc/shared/vmGCOperations.hpp"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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/shared/collectedHeap.hpp"
+#include "gc/shared/collectorPolicy.hpp"
+#include "gc/shared/commandLineFlagConstraintsGC.hpp"
+#include "gc/shared/plab.hpp"
+#include "gc/shared/threadLocalAllocBuffer.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/commandLineFlagRangeList.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/globals_extension.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/align.hpp"
+#include "utilities/defaultStream.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/cms/commandLineFlagConstraintsCMS.hpp"
+#include "gc/g1/commandLineFlagConstraintsG1.hpp"
+#include "gc/parallel/commandLineFlagConstraintsParallel.hpp"
+#endif
+#ifdef COMPILER1
+#include "c1/c1_globals.hpp"
+#endif // COMPILER1
+#ifdef COMPILER2
+#include "opto/c2_globals.hpp"
+#endif // COMPILER2
+
+// Some flags that have default values that indicate that the
+// JVM should automatically determine an appropriate value
+// for that flag. In those cases it is only appropriate for the
+// constraint checking to be done if the user has specified the
+// value(s) of the flag(s) on the command line. In the constraint
+// checking functions, FLAG_IS_CMDLINE() is used to check if
+// the flag has been set by the user and so should be checked.
+
+// As ParallelGCThreads differs among GC modes, we need constraint function.
+Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) {
+ Flag::Error status = Flag::SUCCESS;
+
+#if INCLUDE_ALL_GCS
+ status = ParallelGCThreadsConstraintFuncParallel(value, verbose);
+ if (status != Flag::SUCCESS) {
+ return status;
+ }
+
+ status = ParallelGCThreadsConstraintFuncCMS(value, verbose);
+ if (status != Flag::SUCCESS) {
+ return status;
+ }
+#endif
+
+ return status;
+}
+
+// As ConcGCThreads should be smaller than ParallelGCThreads,
+// we need constraint function.
+Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) {
+#if INCLUDE_ALL_GCS
+ // CMS and G1 GCs use ConcGCThreads.
+ if ((UseConcMarkSweepGC || UseG1GC) && (value > ParallelGCThreads)) {
+ CommandLineError::print(verbose,
+ "ConcGCThreads (" UINT32_FORMAT ") must be "
+ "less than or equal to ParallelGCThreads (" UINT32_FORMAT ")\n",
+ value, ParallelGCThreads);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+#endif
+ return Flag::SUCCESS;
+}
+
+static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) {
+#if INCLUDE_ALL_GCS
+ if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value < PLAB::min_size())) {
+ CommandLineError::print(verbose,
+ "%s (" SIZE_FORMAT ") must be "
+ "greater than or equal to ergonomic PLAB minimum size (" SIZE_FORMAT ")\n",
+ name, value, PLAB::min_size());
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+#endif // INCLUDE_ALL_GCS
+ return Flag::SUCCESS;
+}
+
+Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) {
+#if INCLUDE_ALL_GCS
+ if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value > PLAB::max_size())) {
+ CommandLineError::print(verbose,
+ "%s (" SIZE_FORMAT ") must be "
+ "less than or equal to ergonomic PLAB maximum size (" SIZE_FORMAT ")\n",
+ name, value, PLAB::max_size());
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+#endif // INCLUDE_ALL_GCS
+ return Flag::SUCCESS;
+}
+
+static Flag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) {
+ Flag::Error status = MinPLABSizeBounds(name, value, verbose);
+
+ if (status == Flag::SUCCESS) {
+ return MaxPLABSizeBounds(name, value, verbose);
+ }
+ return status;
+}
+
+Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) {
+ return MinMaxPLABSizeBounds("YoungPLABSize", value, verbose);
+}
+
+Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) {
+ Flag::Error status = Flag::SUCCESS;
+
+#if INCLUDE_ALL_GCS
+ if (UseConcMarkSweepGC) {
+ return OldPLABSizeConstraintFuncCMS(value, verbose);
+ } else {
+ status = MinMaxPLABSizeBounds("OldPLABSize", value, verbose);
+ }
+#endif
+ return status;
+}
+
+Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) {
+ if (value > MaxHeapFreeRatio) {
+ CommandLineError::print(verbose,
+ "MinHeapFreeRatio (" UINTX_FORMAT ") must be "
+ "less than or equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n",
+ value, MaxHeapFreeRatio);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) {
+ if (value < MinHeapFreeRatio) {
+ CommandLineError::print(verbose,
+ "MaxHeapFreeRatio (" UINTX_FORMAT ") must be "
+ "greater than or equal to MinHeapFreeRatio (" UINTX_FORMAT ")\n",
+ value, MinHeapFreeRatio);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+static Flag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) {
+ if ((softRef > 0) && ((maxHeap / M) > (max_uintx / softRef))) {
+ CommandLineError::print(verbose,
+ "Desired lifetime of SoftReferences cannot be expressed correctly. "
+ "MaxHeapSize (" SIZE_FORMAT ") or SoftRefLRUPolicyMSPerMB "
+ "(" INTX_FORMAT ") is too large\n",
+ maxHeap, softRef);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) {
+ return CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(MaxHeapSize, value, verbose);
+}
+
+Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) {
+ if (value > MarkStackSizeMax) {
+ CommandLineError::print(verbose,
+ "MarkStackSize (" SIZE_FORMAT ") must be "
+ "less than or equal to MarkStackSizeMax (" SIZE_FORMAT ")\n",
+ value, MarkStackSizeMax);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) {
+ if (value > MaxMetaspaceFreeRatio) {
+ CommandLineError::print(verbose,
+ "MinMetaspaceFreeRatio (" UINTX_FORMAT ") must be "
+ "less than or equal to MaxMetaspaceFreeRatio (" UINTX_FORMAT ")\n",
+ value, MaxMetaspaceFreeRatio);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) {
+ if (value < MinMetaspaceFreeRatio) {
+ CommandLineError::print(verbose,
+ "MaxMetaspaceFreeRatio (" UINTX_FORMAT ") must be "
+ "greater than or equal to MinMetaspaceFreeRatio (" UINTX_FORMAT ")\n",
+ value, MinMetaspaceFreeRatio);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) {
+#if INCLUDE_ALL_GCS
+ Flag::Error status = InitialTenuringThresholdConstraintFuncParallel(value, verbose);
+ if (status != Flag::SUCCESS) {
+ return status;
+ }
+#endif
+
+ return Flag::SUCCESS;
+}
+
+Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) {
+#if INCLUDE_ALL_GCS
+ Flag::Error status = MaxTenuringThresholdConstraintFuncParallel(value, verbose);
+ if (status != Flag::SUCCESS) {
+ return status;
+ }
+#endif
+
+ // MaxTenuringThreshold=0 means NeverTenure=false && AlwaysTenure=true
+ if ((value == 0) && (NeverTenure || !AlwaysTenure)) {
+ CommandLineError::print(verbose,
+ "MaxTenuringThreshold (0) should match to NeverTenure=false "
+ "&& AlwaysTenure=true. But we have NeverTenure=%s "
+ "AlwaysTenure=%s\n",
+ NeverTenure ? "true" : "false",
+ AlwaysTenure ? "true" : "false");
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) {
+#if INCLUDE_ALL_GCS
+ Flag::Error status = MaxGCPauseMillisConstraintFuncG1(value, verbose);
+ if (status != Flag::SUCCESS) {
+ return status;
+ }
+#endif
+
+ return Flag::SUCCESS;
+}
+
+Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) {
+#if INCLUDE_ALL_GCS
+ Flag::Error status = GCPauseIntervalMillisConstraintFuncG1(value, verbose);
+ if (status != Flag::SUCCESS) {
+ return status;
+ }
+#endif
+
+ return Flag::SUCCESS;
+}
+
+Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) {
+ size_t aligned_max = align_down(max_uintx/2, Metaspace::reserve_alignment_words());
+ if (value > aligned_max) {
+ CommandLineError::print(verbose,
+ "InitialBootClassLoaderMetaspaceSize (" SIZE_FORMAT ") must be "
+ "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n",
+ value, aligned_max);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+// To avoid an overflow by 'align_up(value, alignment)'.
+static Flag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) {
+ size_t aligned_max = ((max_uintx - alignment) & ~(alignment-1));
+ if (value > aligned_max) {
+ CommandLineError::print(verbose,
+ "%s (" SIZE_FORMAT ") must be "
+ "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n",
+ name, value, aligned_max);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) {
+ size_t heap_alignment;
+
+#if INCLUDE_ALL_GCS
+ if (UseG1GC) {
+ // For G1 GC, we don't know until G1CollectorPolicy is created.
+ heap_alignment = MaxSizeForHeapAlignmentG1();
+ } else
+#endif
+ {
+ heap_alignment = CollectorPolicy::compute_heap_alignment();
+ }
+
+ return MaxSizeForAlignment(name, value, heap_alignment, verbose);
+}
+
+Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) {
+ return MaxSizeForHeapAlignment("InitialHeapSize", value, verbose);
+}
+
+Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) {
+ Flag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose);
+
+ if (status == Flag::SUCCESS) {
+ status = CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(value, SoftRefLRUPolicyMSPerMB, verbose);
+ }
+ return status;
+}
+
+Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) {
+ // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value.
+ // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx.
+ if (UseCompressedOops && FLAG_IS_ERGO(MaxHeapSize) && (value > (max_uintx - MaxHeapSize))) {
+ CommandLineError::print(verbose,
+ "HeapBaseMinAddress (" SIZE_FORMAT ") or MaxHeapSize (" SIZE_FORMAT ") is too large. "
+ "Sum of them must be less than or equal to maximum of size_t (" SIZE_FORMAT ")\n",
+ value, MaxHeapSize, max_uintx);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+
+ return MaxSizeForHeapAlignment("HeapBaseMinAddress", value, verbose);
+}
+
+Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) {
+#if INCLUDE_ALL_GCS
+ Flag::Error status = NewSizeConstraintFuncG1(value, verbose);
+ if (status != Flag::SUCCESS) {
+ return status;
+ }
+#endif
+
+ return Flag::SUCCESS;
+}
+
+Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) {
+ // At least, alignment reserve area is needed.
+ if (value < ThreadLocalAllocBuffer::alignment_reserve_in_bytes()) {
+ CommandLineError::print(verbose,
+ "MinTLABSize (" SIZE_FORMAT ") must be "
+ "greater than or equal to reserved area in TLAB (" SIZE_FORMAT ")\n",
+ value, ThreadLocalAllocBuffer::alignment_reserve_in_bytes());
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) {
+ CommandLineError::print(verbose,
+ "MinTLABSize (" SIZE_FORMAT ") must be "
+ "less than or equal to ergonomic TLAB maximum (" SIZE_FORMAT ")\n",
+ value, ThreadLocalAllocBuffer::max_size() * HeapWordSize);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) {
+ // Skip for default value of zero which means set ergonomically.
+ if (FLAG_IS_CMDLINE(TLABSize)) {
+ if (value < MinTLABSize) {
+ CommandLineError::print(verbose,
+ "TLABSize (" SIZE_FORMAT ") must be "
+ "greater than or equal to MinTLABSize (" SIZE_FORMAT ")\n",
+ value, MinTLABSize);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) {
+ CommandLineError::print(verbose,
+ "TLABSize (" SIZE_FORMAT ") must be "
+ "less than or equal to ergonomic TLAB maximum size (" SIZE_FORMAT ")\n",
+ value, (ThreadLocalAllocBuffer::max_size() * HeapWordSize));
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+ return Flag::SUCCESS;
+}
+
+// We will protect overflow from ThreadLocalAllocBuffer::record_slow_allocation(),
+// so AfterMemoryInit type is enough to check.
+Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) {
+ if (UseTLAB) {
+ size_t refill_waste_limit = Thread::current()->tlab().refill_waste_limit();
+
+ // Compare with 'max_uintx' as ThreadLocalAllocBuffer::_refill_waste_limit is 'size_t'.
+ if (refill_waste_limit > (max_uintx - value)) {
+ CommandLineError::print(verbose,
+ "TLABWasteIncrement (" UINTX_FORMAT ") must be "
+ "less than or equal to ergonomic TLAB waste increment maximum size(" SIZE_FORMAT ")\n",
+ value, (max_uintx - refill_waste_limit));
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+ return Flag::SUCCESS;
+}
+
+Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) {
+ if (FLAG_IS_CMDLINE(SurvivorRatio) &&
+ (value > (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()))) {
+ CommandLineError::print(verbose,
+ "SurvivorRatio (" UINTX_FORMAT ") must be "
+ "less than or equal to ergonomic SurvivorRatio maximum (" SIZE_FORMAT ")\n",
+ value,
+ (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()));
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) {
+ if (value > MaxMetaspaceSize) {
+ CommandLineError::print(verbose,
+ "MetaspaceSize (" SIZE_FORMAT ") must be "
+ "less than or equal to MaxMetaspaceSize (" SIZE_FORMAT ")\n",
+ value, MaxMetaspaceSize);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) {
+ if (value < MetaspaceSize) {
+ CommandLineError::print(verbose,
+ "MaxMetaspaceSize (" SIZE_FORMAT ") must be "
+ "greater than or equal to MetaspaceSize (" SIZE_FORMAT ")\n",
+ value, MaxMetaspaceSize);
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) {
+ if (value != 0) {
+ if (!is_power_of_2(value)) {
+ CommandLineError::print(verbose,
+ "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be "
+ "power of 2\n",
+ value);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ if (value < ObjectAlignmentInBytes) {
+ CommandLineError::print(verbose,
+ "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be "
+ "greater than or equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n",
+ value, ObjectAlignmentInBytes);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+ return Flag::SUCCESS;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/commandLineFlagConstraintsGC.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP
+#define SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP
+
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/cms/commandLineFlagConstraintsCMS.hpp"
+#include "gc/g1/commandLineFlagConstraintsG1.hpp"
+#include "gc/parallel/commandLineFlagConstraintsParallel.hpp"
+#endif
+
+/*
+ * Here we have GC arguments constraints functions, which are called automatically
+ * whenever flag's value changes. If the constraint fails the function should return
+ * an appropriate error value.
+ */
+
+Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose);
+Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose);
+Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose);
+Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose);
+Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose);
+Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose);
+Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose);
+Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose);
+Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose);
+
+Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose);
+Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose);
+Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose);
+Flag::Error NewSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose);
+Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose);
+Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose);
+
+// Internal
+Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose);
+
+#endif // SHARE_GC_SHARED_COMMANDLINEFLAGCONSTRAINTSGC_HPP
--- a/src/hotspot/share/gc/shared/gcArguments.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/gcArguments.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -31,16 +31,26 @@
#include "utilities/macros.hpp"
void GCArguments::initialize() {
-#if INCLUDE_ALL_GCS
+ if (FullGCALot && FLAG_IS_DEFAULT(MarkSweepAlwaysCompactCount)) {
+ MarkSweepAlwaysCompactCount = 1; // Move objects every gc.
+ }
+
+ if (!(UseParallelGC || UseParallelOldGC) && FLAG_IS_DEFAULT(ScavengeBeforeFullGC)) {
+ FLAG_SET_DEFAULT(ScavengeBeforeFullGC, false);
+ }
+
+ if (GCTimeLimit == 100) {
+ // Turn off gc-overhead-limit-exceeded checks
+ FLAG_SET_DEFAULT(UseGCOverheadLimit, false);
+ }
+
if (MinHeapFreeRatio == 100) {
// Keeping the heap 100% free is hard ;-) so limit it to 99%.
FLAG_SET_ERGO(uintx, MinHeapFreeRatio, 99);
}
- // If class unloading is disabled, also disable concurrent class unloading.
if (!ClassUnloading) {
- FLAG_SET_CMDLINE(bool, CMSClassUnloadingEnabled, false);
+ // If class unloading is disabled, also disable concurrent class unloading.
FLAG_SET_CMDLINE(bool, ClassUnloadingWithConcurrentMark, false);
}
-#endif // INCLUDE_ALL_GCS
}
--- a/src/hotspot/share/gc/shared/gcStats.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/gcStats.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -31,9 +31,3 @@
AdaptiveSizePolicyWeight,
PromotedPadding);
}
-
-CMSGCStats::CMSGCStats() {
- _avg_promoted = new AdaptivePaddedNoZeroDevAverage(
- CMSExpAvgFactor,
- PromotedPadding);
-}
--- a/src/hotspot/share/gc/shared/gcStats.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/gcStats.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -58,13 +58,4 @@
}
};
-class CMSGCStats : public GCStats {
- public:
- CMSGCStats();
-
- virtual Name kind() {
- return CMSGCStatsKind;
- }
-};
-
#endif // SHARE_VM_GC_SHARED_GCSTATS_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/gcThreadLocalData.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_SHARED_GCTHREADLOCALDATA_HPP
+#define SHARE_GC_SHARED_GCTHREADLOCALDATA_HPP
+
+#include "utilities/globalDefinitions.hpp"
+
+// Thread local data area for GC-specific information. Each GC
+// is free to decide the internal structure and contents of this
+// area. It is represented as a 64-bit aligned opaque blob to
+// avoid circular dependencies between Thread and all GCs. For
+// the same reason, the size of the data area is hard coded to
+// provide enough space for all current GCs. Adjust the size if
+// needed, but avoid making it excessively large as it adds to
+// the memory overhead of creating a thread.
+//
+// Use Thread::gc_data<T>() to access the data, where T is the
+// GC-specific type describing the structure of the data. GCs
+// should consider placing frequently accessed fields first in
+// T, so that field offsets relative to Thread are small, which
+// often allows for a more compact instruction encoding.
+typedef uint64_t GCThreadLocalData[14]; // 112 bytes
+
+#endif // SHARE_GC_SHARED_GCTHREADLOCALDATA_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/gc_globals.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,771 @@
+/*
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_SHARED_GC_GLOBALS_HPP
+#define SHARE_GC_SHARED_GC_GLOBALS_HPP
+
+#include "gc/serial/serial_globals.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/cms/cms_globals.hpp"
+#include "gc/g1/g1_globals.hpp"
+#include "gc/parallel/parallel_globals.hpp"
+#endif
+
+#define GC_FLAGS(develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+ \
+ ALL_GCS_ONLY(GC_CMS_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable)) \
+ \
+ ALL_GCS_ONLY(GC_G1_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable)) \
+ \
+ ALL_GCS_ONLY(GC_PARALLEL_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable)) \
+ \
+ GC_SERIAL_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+ \
+ /* gc */ \
+ \
+ product(bool, UseConcMarkSweepGC, false, \
+ "Use Concurrent Mark-Sweep GC in the old generation") \
+ \
+ product(bool, UseSerialGC, false, \
+ "Use the Serial garbage collector") \
+ \
+ product(bool, UseG1GC, false, \
+ "Use the Garbage-First garbage collector") \
+ \
+ product(bool, UseParallelGC, false, \
+ "Use the Parallel Scavenge garbage collector") \
+ \
+ product(bool, UseParallelOldGC, false, \
+ "Use the Parallel Old garbage collector") \
+ \
+ product(uint, ParallelGCThreads, 0, \
+ "Number of parallel threads parallel gc will use") \
+ constraint(ParallelGCThreadsConstraintFunc,AfterErgo) \
+ \
+ diagnostic(bool, UseSemaphoreGCThreadsSynchronization, true, \
+ "Use semaphore synchronization for the GC Threads, " \
+ "instead of synchronization based on mutexes") \
+ \
+ product(bool, UseDynamicNumberOfGCThreads, true, \
+ "Dynamically choose the number of threads up to a maximum of " \
+ "ParallelGCThreads parallel collectors will use for garbage " \
+ "collection work") \
+ \
+ diagnostic(bool, InjectGCWorkerCreationFailure, false, \
+ "Inject thread creation failures for " \
+ "UseDynamicNumberOfGCThreads") \
+ \
+ diagnostic(bool, ForceDynamicNumberOfGCThreads, false, \
+ "Force dynamic selection of the number of " \
+ "parallel threads parallel gc will use to aid debugging") \
+ \
+ product(size_t, HeapSizePerGCThread, ScaleForWordSize(32*M), \
+ "Size of heap (bytes) per GC thread used in calculating the " \
+ "number of GC threads") \
+ range((size_t)os::vm_page_size(), (size_t)max_uintx) \
+ \
+ product(uint, ConcGCThreads, 0, \
+ "Number of threads concurrent gc will use") \
+ constraint(ConcGCThreadsConstraintFunc,AfterErgo) \
+ \
+ product(uint, GCTaskTimeStampEntries, 200, \
+ "Number of time stamp entries per gc worker thread") \
+ range(1, max_jint) \
+ \
+ product(bool, AlwaysTenure, false, \
+ "Always tenure objects in eden (ParallelGC only)") \
+ \
+ product(bool, NeverTenure, false, \
+ "Never tenure objects in eden, may tenure on overflow " \
+ "(ParallelGC only)") \
+ \
+ product(bool, ScavengeBeforeFullGC, true, \
+ "Scavenge youngest generation before each full GC.") \
+ \
+ product(bool, ExplicitGCInvokesConcurrent, false, \
+ "A System.gc() request invokes a concurrent collection; " \
+ "(effective only when using concurrent collectors)") \
+ \
+ product(bool, GCLockerInvokesConcurrent, false, \
+ "The exit of a JNI critical section necessitating a scavenge, " \
+ "also kicks off a background concurrent collection") \
+ \
+ product(uintx, GCLockerEdenExpansionPercent, 5, \
+ "How much the GC can expand the eden by while the GC locker " \
+ "is active (as a percentage)") \
+ range(0, 100) \
+ \
+ diagnostic(uintx, GCLockerRetryAllocationCount, 2, \
+ "Number of times to retry allocations when " \
+ "blocked by the GC locker") \
+ range(0, max_uintx) \
+ \
+ product(uintx, ParallelGCBufferWastePct, 10, \
+ "Wasted fraction of parallel allocation buffer") \
+ range(0, 100) \
+ \
+ product(uintx, TargetPLABWastePct, 10, \
+ "Target wasted space in last buffer as percent of overall " \
+ "allocation") \
+ range(1, 100) \
+ \
+ product(uintx, PLABWeight, 75, \
+ "Percentage (0-100) used to weight the current sample when " \
+ "computing exponentially decaying average for ResizePLAB") \
+ range(0, 100) \
+ \
+ product(bool, ResizePLAB, true, \
+ "Dynamically resize (survivor space) promotion LAB's") \
+ \
+ product(int, ParGCArrayScanChunk, 50, \
+ "Scan a subset of object array and push remainder, if array is " \
+ "bigger than this") \
+ range(1, max_jint/3) \
+ \
+ product(uintx, OldPLABWeight, 50, \
+ "Percentage (0-100) used to weight the current sample when " \
+ "computing exponentially decaying average for resizing " \
+ "OldPLABSize") \
+ range(0, 100) \
+ \
+ product(bool, ResizeOldPLAB, true, \
+ "Dynamically resize (old gen) promotion LAB's") \
+ \
+ product(bool, AlwaysPreTouch, false, \
+ "Force all freshly committed pages to be pre-touched") \
+ \
+ product(size_t, PreTouchParallelChunkSize, 1 * G, \
+ "Per-thread chunk size for parallel memory pre-touch.") \
+ range(1, SIZE_MAX / 2) \
+ \
+ /* where does the range max value of (max_jint - 1) come from? */ \
+ product(size_t, MarkStackSizeMax, NOT_LP64(4*M) LP64_ONLY(512*M), \
+ "Maximum size of marking stack") \
+ range(1, (max_jint - 1)) \
+ \
+ product(size_t, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \
+ "Size of marking stack") \
+ constraint(MarkStackSizeConstraintFunc,AfterErgo) \
+ \
+ develop(bool, VerifyBlockOffsetArray, false, \
+ "Do (expensive) block offset array verification") \
+ \
+ diagnostic(bool, BlockOffsetArrayUseUnallocatedBlock, false, \
+ "Maintain _unallocated_block in BlockOffsetArray " \
+ "(currently applicable only to CMS collector)") \
+ \
+ product(intx, RefDiscoveryPolicy, 0, \
+ "Select type of reference discovery policy: " \
+ "reference-based(0) or referent-based(1)") \
+ range(ReferenceProcessor::DiscoveryPolicyMin, \
+ ReferenceProcessor::DiscoveryPolicyMax) \
+ \
+ product(bool, ParallelRefProcEnabled, false, \
+ "Enable parallel reference processing whenever possible") \
+ \
+ product(bool, ParallelRefProcBalancingEnabled, true, \
+ "Enable balancing of reference processing queues") \
+ \
+ product(uintx, InitiatingHeapOccupancyPercent, 45, \
+ "The percent occupancy (IHOP) of the current old generation " \
+ "capacity above which a concurrent mark cycle will be initiated " \
+ "Its value may change over time if adaptive IHOP is enabled, " \
+ "otherwise the value remains constant. " \
+ "In the latter case a value of 0 will result as frequent as " \
+ "possible concurrent marking cycles. A value of 100 disables " \
+ "concurrent marking. " \
+ "Fragmentation waste in the old generation is not considered " \
+ "free space in this calculation. (G1 collector only)") \
+ range(0, 100) \
+ \
+ notproduct(bool, ScavengeALot, false, \
+ "Force scavenge at every Nth exit from the runtime system " \
+ "(N=ScavengeALotInterval)") \
+ \
+ develop(bool, FullGCALot, false, \
+ "Force full gc at every Nth exit from the runtime system " \
+ "(N=FullGCALotInterval)") \
+ \
+ notproduct(bool, GCALotAtAllSafepoints, false, \
+ "Enforce ScavengeALot/GCALot at all potential safepoints") \
+ \
+ notproduct(bool, PromotionFailureALot, false, \
+ "Use promotion failure handling on every youngest generation " \
+ "collection") \
+ \
+ develop(uintx, PromotionFailureALotCount, 1000, \
+ "Number of promotion failures occurring at PLAB " \
+ "refill attempts (ParNew) or promotion attempts " \
+ "(other young collectors)") \
+ \
+ develop(uintx, PromotionFailureALotInterval, 5, \
+ "Total collections between promotion failures a lot") \
+ \
+ experimental(uintx, WorkStealingSleepMillis, 1, \
+ "Sleep time when sleep is used for yields") \
+ \
+ experimental(uintx, WorkStealingYieldsBeforeSleep, 5000, \
+ "Number of yields before a sleep is done during work stealing") \
+ \
+ experimental(uintx, WorkStealingHardSpins, 4096, \
+ "Number of iterations in a spin loop between checks on " \
+ "time out of hard spin") \
+ \
+ experimental(uintx, WorkStealingSpinToYieldRatio, 10, \
+ "Ratio of hard spins to calls to yield") \
+ \
+ develop(uintx, ObjArrayMarkingStride, 2048, \
+ "Number of object array elements to push onto the marking stack " \
+ "before pushing a continuation entry") \
+ \
+ develop(bool, MetadataAllocationFailALot, false, \
+ "Fail metadata allocations at intervals controlled by " \
+ "MetadataAllocationFailALotInterval") \
+ \
+ develop(uintx, MetadataAllocationFailALotInterval, 1000, \
+ "Metadata allocation failure a lot interval") \
+ \
+ notproduct(bool, ExecuteInternalVMTests, false, \
+ "Enable execution of internal VM tests") \
+ \
+ notproduct(bool, VerboseInternalVMTests, false, \
+ "Turn on logging for internal VM tests.") \
+ \
+ product(bool, ExecutingUnitTests, false, \
+ "Whether the JVM is running unit tests or not") \
+ \
+ product_pd(bool, UseTLAB, "Use thread-local object allocation") \
+ \
+ product_pd(bool, ResizeTLAB, \
+ "Dynamically resize TLAB size for threads") \
+ \
+ product(bool, ZeroTLAB, false, \
+ "Zero out the newly created TLAB") \
+ \
+ product(bool, TLABStats, true, \
+ "Provide more detailed and expensive TLAB statistics.") \
+ \
+ product_pd(bool, NeverActAsServerClassMachine, \
+ "Never act like a server-class machine") \
+ \
+ product(bool, AlwaysActAsServerClassMachine, false, \
+ "Always act like a server-class machine") \
+ \
+ product_pd(uint64_t, MaxRAM, \
+ "Real memory size (in bytes) used to set maximum heap size") \
+ range(0, 0XFFFFFFFFFFFFFFFF) \
+ \
+ product(bool, AggressiveHeap, false, \
+ "Optimize heap options for long-running memory intensive apps") \
+ \
+ product(size_t, ErgoHeapSizeLimit, 0, \
+ "Maximum ergonomically set heap size (in bytes); zero means use " \
+ "MaxRAM * MaxRAMPercentage / 100") \
+ range(0, max_uintx) \
+ \
+ product(uintx, MaxRAMFraction, 4, \
+ "Maximum fraction (1/n) of real memory used for maximum heap " \
+ "size. " \
+ "Deprecated, use MaxRAMPercentage instead") \
+ range(1, max_uintx) \
+ \
+ product(uintx, MinRAMFraction, 2, \
+ "Minimum fraction (1/n) of real memory used for maximum heap " \
+ "size on systems with small physical memory size. " \
+ "Deprecated, use MinRAMPercentage instead") \
+ range(1, max_uintx) \
+ \
+ product(uintx, InitialRAMFraction, 64, \
+ "Fraction (1/n) of real memory used for initial heap size. " \
+ "Deprecated, use InitialRAMPercentage instead") \
+ range(1, max_uintx) \
+ \
+ product(double, MaxRAMPercentage, 25.0, \
+ "Maximum percentage of real memory used for maximum heap size") \
+ range(0.0, 100.0) \
+ \
+ product(double, MinRAMPercentage, 50.0, \
+ "Minimum percentage of real memory used for maximum heap" \
+ "size on systems with small physical memory size") \
+ range(0.0, 100.0) \
+ \
+ product(double, InitialRAMPercentage, 1.5625, \
+ "Percentage of real memory used for initial heap size") \
+ range(0.0, 100.0) \
+ \
+ product(int, ActiveProcessorCount, -1, \
+ "Specify the CPU count the VM should use and report as active") \
+ \
+ develop(uintx, MaxVirtMemFraction, 2, \
+ "Maximum fraction (1/n) of virtual memory used for ergonomically "\
+ "determining maximum heap size") \
+ \
+ product(bool, UseAdaptiveSizePolicy, true, \
+ "Use adaptive generation sizing policies") \
+ \
+ product(bool, UsePSAdaptiveSurvivorSizePolicy, true, \
+ "Use adaptive survivor sizing policies") \
+ \
+ product(bool, UseAdaptiveGenerationSizePolicyAtMinorCollection, true, \
+ "Use adaptive young-old sizing policies at minor collections") \
+ \
+ product(bool, UseAdaptiveGenerationSizePolicyAtMajorCollection, true, \
+ "Use adaptive young-old sizing policies at major collections") \
+ \
+ product(bool, UseAdaptiveSizePolicyWithSystemGC, false, \
+ "Include statistics from System.gc() for adaptive size policy") \
+ \
+ product(bool, UseAdaptiveGCBoundary, false, \
+ "Allow young-old boundary to move") \
+ \
+ develop(intx, PSAdaptiveSizePolicyResizeVirtualSpaceAlot, -1, \
+ "Resize the virtual spaces of the young or old generations") \
+ range(-1, 1) \
+ \
+ product(uintx, AdaptiveSizeThroughPutPolicy, 0, \
+ "Policy for changing generation size for throughput goals") \
+ range(0, 1) \
+ \
+ product(uintx, AdaptiveSizePolicyInitializingSteps, 20, \
+ "Number of steps where heuristics is used before data is used") \
+ range(0, max_uintx) \
+ \
+ develop(uintx, AdaptiveSizePolicyReadyThreshold, 5, \
+ "Number of collections before the adaptive sizing is started") \
+ \
+ product(uintx, AdaptiveSizePolicyOutputInterval, 0, \
+ "Collection interval for printing information; zero means never") \
+ range(0, max_uintx) \
+ \
+ product(bool, UseAdaptiveSizePolicyFootprintGoal, true, \
+ "Use adaptive minimum footprint as a goal") \
+ \
+ product(uintx, AdaptiveSizePolicyWeight, 10, \
+ "Weight given to exponential resizing, between 0 and 100") \
+ range(0, 100) \
+ \
+ product(uintx, AdaptiveTimeWeight, 25, \
+ "Weight given to time in adaptive policy, between 0 and 100") \
+ range(0, 100) \
+ \
+ product(uintx, PausePadding, 1, \
+ "How much buffer to keep for pause time") \
+ range(0, max_juint) \
+ \
+ product(uintx, PromotedPadding, 3, \
+ "How much buffer to keep for promotion failure") \
+ range(0, max_juint) \
+ \
+ product(uintx, SurvivorPadding, 3, \
+ "How much buffer to keep for survivor overflow") \
+ range(0, max_juint) \
+ \
+ product(uintx, ThresholdTolerance, 10, \
+ "Allowed collection cost difference between generations") \
+ range(0, 100) \
+ \
+ product(uintx, AdaptiveSizePolicyCollectionCostMargin, 50, \
+ "If collection costs are within margin, reduce both by full " \
+ "delta") \
+ range(0, 100) \
+ \
+ product(uintx, YoungGenerationSizeIncrement, 20, \
+ "Adaptive size percentage change in young generation") \
+ range(0, 100) \
+ \
+ product(uintx, YoungGenerationSizeSupplement, 80, \
+ "Supplement to YoungedGenerationSizeIncrement used at startup") \
+ range(0, 100) \
+ \
+ product(uintx, YoungGenerationSizeSupplementDecay, 8, \
+ "Decay factor to YoungedGenerationSizeSupplement") \
+ range(1, max_uintx) \
+ \
+ product(uintx, TenuredGenerationSizeIncrement, 20, \
+ "Adaptive size percentage change in tenured generation") \
+ range(0, 100) \
+ \
+ product(uintx, TenuredGenerationSizeSupplement, 80, \
+ "Supplement to TenuredGenerationSizeIncrement used at startup") \
+ range(0, 100) \
+ \
+ product(uintx, TenuredGenerationSizeSupplementDecay, 2, \
+ "Decay factor to TenuredGenerationSizeIncrement") \
+ range(1, max_uintx) \
+ \
+ product(uintx, MaxGCPauseMillis, max_uintx - 1, \
+ "Adaptive size policy maximum GC pause time goal in millisecond, "\
+ "or (G1 Only) the maximum GC time per MMU time slice") \
+ range(1, max_uintx - 1) \
+ constraint(MaxGCPauseMillisConstraintFunc,AfterErgo) \
+ \
+ product(uintx, GCPauseIntervalMillis, 0, \
+ "Time slice for MMU specification") \
+ constraint(GCPauseIntervalMillisConstraintFunc,AfterErgo) \
+ \
+ product(uintx, MaxGCMinorPauseMillis, max_uintx, \
+ "Adaptive size policy maximum GC minor pause time goal " \
+ "in millisecond") \
+ range(0, max_uintx) \
+ \
+ product(uintx, GCTimeRatio, 99, \
+ "Adaptive size policy application time to GC time ratio") \
+ range(0, max_juint) \
+ \
+ product(uintx, AdaptiveSizeDecrementScaleFactor, 4, \
+ "Adaptive size scale down factor for shrinking") \
+ range(1, max_uintx) \
+ \
+ product(bool, UseAdaptiveSizeDecayMajorGCCost, true, \
+ "Adaptive size decays the major cost for long major intervals") \
+ \
+ product(uintx, AdaptiveSizeMajorGCDecayTimeScale, 10, \
+ "Time scale over which major costs decay") \
+ range(0, max_uintx) \
+ \
+ product(uintx, MinSurvivorRatio, 3, \
+ "Minimum ratio of young generation/survivor space size") \
+ range(3, max_uintx) \
+ \
+ product(uintx, InitialSurvivorRatio, 8, \
+ "Initial ratio of young generation/survivor space size") \
+ range(0, max_uintx) \
+ \
+ product(size_t, BaseFootPrintEstimate, 256*M, \
+ "Estimate of footprint other than Java Heap") \
+ range(0, max_uintx) \
+ \
+ product(bool, UseGCOverheadLimit, true, \
+ "Use policy to limit of proportion of time spent in GC " \
+ "before an OutOfMemory error is thrown") \
+ \
+ product(uintx, GCTimeLimit, 98, \
+ "Limit of the proportion of time spent in GC before " \
+ "an OutOfMemoryError is thrown (used with GCHeapFreeLimit)") \
+ range(0, 100) \
+ \
+ product(uintx, GCHeapFreeLimit, 2, \
+ "Minimum percentage of free space after a full GC before an " \
+ "OutOfMemoryError is thrown (used with GCTimeLimit)") \
+ range(0, 100) \
+ \
+ develop(uintx, AdaptiveSizePolicyGCTimeLimitThreshold, 5, \
+ "Number of consecutive collections before gc time limit fires") \
+ range(1, max_uintx) \
+ \
+ product(intx, PrefetchCopyIntervalInBytes, -1, \
+ "How far ahead to prefetch destination area (<= 0 means off)") \
+ range(-1, max_jint) \
+ \
+ product(intx, PrefetchScanIntervalInBytes, -1, \
+ "How far ahead to prefetch scan area (<= 0 means off)") \
+ range(-1, max_jint) \
+ \
+ product(intx, PrefetchFieldsAhead, -1, \
+ "How many fields ahead to prefetch in oop scan (<= 0 means off)") \
+ range(-1, max_jint) \
+ \
+ diagnostic(bool, VerifyDuringStartup, false, \
+ "Verify memory system before executing any Java code " \
+ "during VM initialization") \
+ \
+ diagnostic(bool, VerifyBeforeExit, trueInDebug, \
+ "Verify system before exiting") \
+ \
+ diagnostic(bool, VerifyBeforeGC, false, \
+ "Verify memory system before GC") \
+ \
+ diagnostic(bool, VerifyAfterGC, false, \
+ "Verify memory system after GC") \
+ \
+ diagnostic(bool, VerifyDuringGC, false, \
+ "Verify memory system during GC (between phases)") \
+ \
+ diagnostic(ccstrlist, VerifyGCType, "", \
+ "GC type(s) to verify when Verify*GC is enabled." \
+ "Available types are collector specific.") \
+ \
+ diagnostic(ccstrlist, VerifySubSet, "", \
+ "Memory sub-systems to verify when Verify*GC flag(s) " \
+ "are enabled. One or more sub-systems can be specified " \
+ "in a comma separated string. Sub-systems are: " \
+ "threads, heap, symbol_table, string_table, codecache, " \
+ "dictionary, classloader_data_graph, metaspace, jni_handles, " \
+ "codecache_oops") \
+ \
+ diagnostic(bool, GCParallelVerificationEnabled, true, \
+ "Enable parallel memory system verification") \
+ \
+ diagnostic(bool, DeferInitialCardMark, false, \
+ "When +ReduceInitialCardMarks, explicitly defer any that " \
+ "may arise from new_pre_store_barrier") \
+ \
+ product(bool, UseCondCardMark, false, \
+ "Check for already marked card before updating card table") \
+ \
+ diagnostic(bool, VerifyRememberedSets, false, \
+ "Verify GC remembered sets") \
+ \
+ diagnostic(bool, VerifyObjectStartArray, true, \
+ "Verify GC object start array if verify before/after") \
+ \
+ product(bool, DisableExplicitGC, false, \
+ "Ignore calls to System.gc()") \
+ \
+ product(bool, BindGCTaskThreadsToCPUs, false, \
+ "Bind GCTaskThreads to CPUs if possible") \
+ \
+ product(bool, UseGCTaskAffinity, false, \
+ "Use worker affinity when asking for GCTasks") \
+ \
+ 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") \
+ range(0, max_intx) \
+ \
+ notproduct(intx, ScavengeALotInterval, 1, \
+ "Interval between which scavenge will occur with +ScavengeALot") \
+ \
+ notproduct(intx, FullGCALotInterval, 1, \
+ "Interval between which full gc will occur with +FullGCALot") \
+ \
+ notproduct(intx, FullGCALotStart, 0, \
+ "For which invocation to start FullGCAlot") \
+ \
+ notproduct(intx, FullGCALotDummies, 32*K, \
+ "Dummy object allocated with +FullGCALot, forcing all objects " \
+ "to move") \
+ \
+ /* gc parameters */ \
+ product(size_t, InitialHeapSize, 0, \
+ "Initial heap size (in bytes); zero means use ergonomics") \
+ constraint(InitialHeapSizeConstraintFunc,AfterErgo) \
+ \
+ product(size_t, MaxHeapSize, ScaleForWordSize(96*M), \
+ "Maximum heap size (in bytes)") \
+ constraint(MaxHeapSizeConstraintFunc,AfterErgo) \
+ \
+ product(size_t, OldSize, ScaleForWordSize(4*M), \
+ "Initial tenured generation size (in bytes)") \
+ range(0, max_uintx) \
+ \
+ product(size_t, NewSize, ScaleForWordSize(1*M), \
+ "Initial new generation size (in bytes)") \
+ constraint(NewSizeConstraintFunc,AfterErgo) \
+ \
+ product(size_t, MaxNewSize, max_uintx, \
+ "Maximum new generation size (in bytes), max_uintx means set " \
+ "ergonomically") \
+ range(0, max_uintx) \
+ \
+ product_pd(size_t, HeapBaseMinAddress, \
+ "OS specific low limit for heap base address") \
+ constraint(HeapBaseMinAddressConstraintFunc,AfterErgo) \
+ \
+ product(size_t, PretenureSizeThreshold, 0, \
+ "Maximum size in bytes of objects allocated in DefNew " \
+ "generation; zero means no maximum") \
+ range(0, max_uintx) \
+ \
+ product(size_t, MinTLABSize, 2*K, \
+ "Minimum allowed TLAB size (in bytes)") \
+ range(1, max_uintx/2) \
+ constraint(MinTLABSizeConstraintFunc,AfterMemoryInit) \
+ \
+ product(size_t, TLABSize, 0, \
+ "Starting TLAB size (in bytes); zero means set ergonomically") \
+ constraint(TLABSizeConstraintFunc,AfterMemoryInit) \
+ \
+ product(size_t, YoungPLABSize, 4096, \
+ "Size of young gen promotion LAB's (in HeapWords)") \
+ constraint(YoungPLABSizeConstraintFunc,AfterMemoryInit) \
+ \
+ product(size_t, OldPLABSize, 1024, \
+ "Size of old gen promotion LAB's (in HeapWords), or Number " \
+ "of blocks to attempt to claim when refilling CMS LAB's") \
+ constraint(OldPLABSizeConstraintFunc,AfterMemoryInit) \
+ \
+ product(uintx, TLABAllocationWeight, 35, \
+ "Allocation averaging weight") \
+ range(0, 100) \
+ \
+ /* Limit the lower bound of this flag to 1 as it is used */ \
+ /* in a division expression. */ \
+ product(uintx, TLABWasteTargetPercent, 1, \
+ "Percentage of Eden that can be wasted") \
+ range(1, 100) \
+ \
+ product(uintx, TLABRefillWasteFraction, 64, \
+ "Maximum TLAB waste at a refill (internal fragmentation)") \
+ range(1, max_juint) \
+ \
+ product(uintx, TLABWasteIncrement, 4, \
+ "Increment allowed waste at slow allocation") \
+ range(0, max_jint) \
+ constraint(TLABWasteIncrementConstraintFunc,AfterMemoryInit) \
+ \
+ product(uintx, SurvivorRatio, 8, \
+ "Ratio of eden/survivor space size") \
+ range(1, max_uintx-2) \
+ constraint(SurvivorRatioConstraintFunc,AfterMemoryInit) \
+ \
+ product(uintx, NewRatio, 2, \
+ "Ratio of old/new generation sizes") \
+ range(0, max_uintx-1) \
+ \
+ product_pd(size_t, NewSizeThreadIncrease, \
+ "Additional size added to desired new generation size per " \
+ "non-daemon thread (in bytes)") \
+ range(0, max_uintx) \
+ \
+ product(uintx, QueuedAllocationWarningCount, 0, \
+ "Number of times an allocation that queues behind a GC " \
+ "will retry before printing a warning") \
+ range(0, max_uintx) \
+ \
+ diagnostic(uintx, VerifyGCStartAt, 0, \
+ "GC invoke count where +VerifyBefore/AfterGC kicks in") \
+ range(0, max_uintx) \
+ \
+ diagnostic(intx, VerifyGCLevel, 0, \
+ "Generation level at which to start +VerifyBefore/AfterGC") \
+ range(0, 1) \
+ \
+ product(uintx, MaxTenuringThreshold, 15, \
+ "Maximum value for tenuring threshold") \
+ range(0, markOopDesc::max_age + 1) \
+ constraint(MaxTenuringThresholdConstraintFunc,AfterErgo) \
+ \
+ product(uintx, InitialTenuringThreshold, 7, \
+ "Initial value for tenuring threshold") \
+ range(0, markOopDesc::max_age + 1) \
+ constraint(InitialTenuringThresholdConstraintFunc,AfterErgo) \
+ \
+ product(uintx, TargetSurvivorRatio, 50, \
+ "Desired percentage of survivor space used after scavenge") \
+ range(0, 100) \
+ \
+ product(uintx, MarkSweepDeadRatio, 5, \
+ "Percentage (0-100) of the old gen allowed as dead wood. " \
+ "Serial mark sweep treats this as both the minimum and maximum " \
+ "value. " \
+ "CMS uses this value only if it falls back to mark sweep. " \
+ "Par compact uses a variable scale based on the density of the " \
+ "generation and treats this as the maximum value when the heap " \
+ "is either completely full or completely empty. Par compact " \
+ "also has a smaller default value; see arguments.cpp.") \
+ range(0, 100) \
+ \
+ product(uint, MarkSweepAlwaysCompactCount, 4, \
+ "How often should we fully compact the heap (ignoring the dead " \
+ "space parameters)") \
+ range(1, max_juint) \
+ \
+ develop(uintx, GCExpandToAllocateDelayMillis, 0, \
+ "Delay between expansion and allocation (in milliseconds)") \
+ \
+ product(uintx, GCDrainStackTargetSize, 64, \
+ "Number of entries we will try to leave on the stack " \
+ "during parallel gc") \
+ range(0, max_juint)
+
+#endif // SHARE_GC_SHARED_GC_GLOBALS_HPP
--- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -110,11 +110,11 @@
initialize_reserved_region((HeapWord*)heap_rs.base(), (HeapWord*)(heap_rs.base() + heap_rs.size()));
- _rem_set = new CardTableRS(reserved_region());
+ _rem_set = create_rem_set(reserved_region());
_rem_set->initialize();
CardTableBarrierSet *bs = new CardTableBarrierSet(_rem_set);
bs->initialize();
- set_barrier_set(bs);
+ BarrierSet::set_barrier_set(bs);
ReservedSpace young_rs = heap_rs.first_part(_young_gen_spec->max_size(), false, false);
_young_gen = _young_gen_spec->init(young_rs, rem_set());
@@ -127,6 +127,10 @@
return JNI_OK;
}
+CardTableRS* GenCollectedHeap::create_rem_set(const MemRegion& reserved_region) {
+ return new CardTableRS(reserved_region, false /* scan_concurrently */);
+}
+
void GenCollectedHeap::initialize_size_policy(size_t init_eden_size,
size_t init_promo_size,
size_t init_survivor_size) {
--- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -167,6 +167,7 @@
// Returns JNI_OK on success
virtual jint initialize();
+ virtual CardTableRS* create_rem_set(const MemRegion& reserved_region);
void initialize_size_policy(size_t init_eden_size,
size_t init_promo_size,
--- a/src/hotspot/share/gc/shared/genOopClosures.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/genOopClosures.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -22,9 +22,12 @@
*/
#include "precompiled.hpp"
+#include "gc/serial/serial_specialized_oop_closures.hpp"
#include "gc/shared/genOopClosures.inline.hpp"
-#include "gc/shared/specialized_oop_closures.hpp"
#include "memory/iterator.inline.hpp"
+void FilteringClosure::do_oop(oop* p) { do_oop_nv(p); }
+void FilteringClosure::do_oop(narrowOop* p) { do_oop_nv(p); }
+
// Generate Serial GC specialized oop_oop_iterate functions.
SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(ALL_KLASS_OOP_OOP_ITERATE_DEFN)
--- a/src/hotspot/share/gc/shared/genOopClosures.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/genOopClosures.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,7 @@
#include "gc/shared/space.hpp"
#include "oops/access.inline.hpp"
#include "oops/compressedOops.inline.hpp"
+#include "oops/oop.inline.hpp"
inline OopsInGenClosure::OopsInGenClosure(Generation* gen) :
ExtendedOopClosure(gen->ref_processor()), _orig_gen(gen), _rs(NULL) {
--- a/src/hotspot/share/gc/shared/memset_with_concurrent_readers.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/memset_with_concurrent_readers.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,9 +30,6 @@
#include <stddef.h>
#include <string.h>
-// Only used by concurrent collectors.
-#if INCLUDE_ALL_GCS
-
// Fill a block of memory with value, like memset, but with the
// understanding that there may be concurrent readers of that memory.
void memset_with_concurrent_readers(void* to, int value, size_t size);
@@ -50,6 +47,4 @@
#endif // End of target dispatch.
-#endif // INCLUDE_ALL_GCS
-
#endif // SRC_SHARE_VM_GC_SHARED_MEMSETWITHCONCURRENTREADERS_HPP
--- a/src/hotspot/share/gc/shared/oopStorage.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorage.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -687,7 +687,6 @@
}
// Parallel iteration support
-#if INCLUDE_ALL_GCS
static char* not_started_marker_dummy = NULL;
static void* const not_started_marker = ¬_started_marker_dummy;
@@ -737,8 +736,6 @@
return static_cast<Block*>(next);
}
-#endif // INCLUDE_ALL_GCS
-
const char* OopStorage::name() const { return _name; }
#ifndef PRODUCT
--- a/src/hotspot/share/gc/shared/oopStorage.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorage.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -146,11 +146,9 @@
template<typename IsAliveClosure, typename Closure>
inline void weak_oops_do(IsAliveClosure* is_alive, Closure* closure);
-#if INCLUDE_ALL_GCS
// Parallel iteration is for the exclusive use of the GC.
// Other clients must use serial iteration.
template<bool concurrent, bool is_const> class ParState;
-#endif // INCLUDE_ALL_GCS
// Block cleanup functions are for the exclusive use of the GC.
// Both stop deleting if there is an in-progress concurrent iteration.
@@ -244,10 +242,8 @@
template<typename F, typename Storage>
static bool iterate_impl(F f, Storage* storage);
-#if INCLUDE_ALL_GCS
// Implementation support for parallel iteration
class BasicParState;
-#endif // INCLUDE_ALL_GCS
// Wrapper for OopClosure-style function, so it can be used with
// iterate. Assume p is of type oop*. Then cl->do_oop(p) must be a
--- a/src/hotspot/share/gc/shared/oopStorageParState.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorageParState.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,8 +28,6 @@
#include "gc/shared/oopStorage.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-
//////////////////////////////////////////////////////////////////////////////
// Support for parallel and optionally concurrent state iteration.
//
@@ -192,6 +190,4 @@
void weak_oops_do(IsAliveClosure* is_alive, Closure* cl);
};
-#endif // INCLUDE_ALL_GCS
-
#endif // SHARE_GC_SHARED_OOPSTORAGEPARSTATE_HPP
--- a/src/hotspot/share/gc/shared/oopStorageParState.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorageParState.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -30,8 +30,6 @@
#include "metaprogramming/conditional.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-
template<typename F>
class OopStorage::BasicParState::AlwaysTrueFn {
F _f;
@@ -86,6 +84,4 @@
this->iterate(if_alive_fn(is_alive, oop_fn(cl)));
}
-#endif // INCLUDE_ALL_GCS
-
#endif // SHARE_GC_SHARED_OOPSTORAGEPARSTATE_INLINE_HPP
--- a/src/hotspot/share/gc/shared/preservedMarks.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/preservedMarks.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* 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 "gc/shared/workgroup.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
+#include "oops/oop.inline.hpp"
#include "utilities/macros.hpp"
void PreservedMarks::restore() {
--- a/src/hotspot/share/gc/shared/preservedMarks.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/preservedMarks.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,7 +44,7 @@
OopAndMarkOop(oop obj, markOop m) : _o(obj), _m(m) { }
oop get_oop() { return _o; }
- void set_mark() const { _o->set_mark(_m); }
+ inline void set_mark() const;
void set_oop(oop obj) { _o = obj; }
};
typedef Stack<OopAndMarkOop, mtGC> OopAndMarkOopStack;
--- a/src/hotspot/share/gc/shared/preservedMarks.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/preservedMarks.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,7 @@
}
inline void PreservedMarks::init_forwarded_mark(oop obj) {
- obj->init_mark();
+ obj->init_mark_raw();
}
inline void PreservedMarksSet::restore(RestorePreservedMarksTaskExecutor* executor) {
@@ -78,4 +78,8 @@
// cache size to 0.
0 /* max_cache_size */) { }
+void PreservedMarks::OopAndMarkOop::set_mark() const {
+ _o->set_mark_raw(_m);
+}
+
#endif // SHARE_VM_GC_SHARED_PRESERVEDMARKS_INLINE_HPP
--- a/src/hotspot/share/gc/shared/space.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/space.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -397,7 +397,7 @@
} else {
// if the object isn't moving we can just set the mark to the default
// mark and handle it specially later on.
- q->init_mark();
+ q->init_mark_raw();
assert(q->forwardee() == NULL, "should be forwarded to NULL");
}
@@ -695,14 +695,14 @@
// allocate uninitialized int array
typeArrayOop t = (typeArrayOop) allocate(size);
assert(t != NULL, "allocation should succeed");
- t->set_mark(markOopDesc::prototype());
+ t->set_mark_raw(markOopDesc::prototype());
t->set_klass(Universe::intArrayKlassObj());
t->set_length((int)length);
} else {
assert(size == CollectedHeap::min_fill_size(),
"size for smallest fake object doesn't match");
instanceOop obj = (instanceOop) allocate(size);
- obj->set_mark(markOopDesc::prototype());
+ obj->set_mark_raw(markOopDesc::prototype());
obj->set_klass_gap(0);
obj->set_klass(SystemDictionary::Object_klass());
}
--- a/src/hotspot/share/gc/shared/space.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/space.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* 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 "gc/shared/spaceDecorator.hpp"
#include "memory/universe.hpp"
#include "oops/oopsHierarchy.hpp"
+#include "oops/oop.inline.hpp"
#include "runtime/prefetch.inline.hpp"
#include "runtime/safepoint.hpp"
@@ -112,7 +113,7 @@
_allowed_deadspace_words -= dead_length;
CollectedHeap::fill_with_object(dead_start, dead_length);
oop obj = oop(dead_start);
- obj->set_mark(obj->mark()->set_marked());
+ obj->set_mark_raw(obj->mark_raw()->set_marked());
assert(dead_length == (size_t)obj->size(), "bad filler object size");
log_develop_trace(gc, compaction)("Inserting object to dead space: " PTR_FORMAT ", " PTR_FORMAT ", " SIZE_FORMAT "b",
@@ -159,8 +160,8 @@
while (cur_obj < scan_limit) {
assert(!space->scanned_block_is_obj(cur_obj) ||
- oop(cur_obj)->mark()->is_marked() || oop(cur_obj)->mark()->is_unlocked() ||
- oop(cur_obj)->mark()->has_bias_pattern(),
+ oop(cur_obj)->mark_raw()->is_marked() || oop(cur_obj)->mark_raw()->is_unlocked() ||
+ oop(cur_obj)->mark_raw()->has_bias_pattern(),
"these are the only valid states during a mark sweep");
if (space->scanned_block_is_obj(cur_obj) && oop(cur_obj)->is_gc_marked()) {
// prefetch beyond cur_obj
@@ -335,7 +336,7 @@
// copy object and reinit its mark
assert(cur_obj != compaction_top, "everything in this pass should be moving");
Copy::aligned_conjoint_words(cur_obj, compaction_top, size);
- oop(compaction_top)->init_mark();
+ oop(compaction_top)->init_mark_raw();
assert(oop(compaction_top)->klass() != NULL, "should have a class");
debug_only(prev_obj = cur_obj);
--- a/src/hotspot/share/gc/shared/specialized_oop_closures.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/specialized_oop_closures.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,8 +25,10 @@
#ifndef SHARE_VM_GC_SHARED_SPECIALIZED_OOP_CLOSURES_HPP
#define SHARE_VM_GC_SHARED_SPECIALIZED_OOP_CLOSURES_HPP
+#include "gc/serial/serial_specialized_oop_closures.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
+#include "gc/cms/cms_specialized_oop_closures.hpp"
#include "gc/g1/g1_specialized_oop_closures.hpp"
#endif // INCLUDE_ALL_GCS
@@ -36,29 +38,9 @@
// macros in the obvious way to add specializations for new closures.
// Forward declarations.
-class OopClosure;
+class ExtendedOopClosure;
+class NoHeaderExtendedOopClosure;
class OopsInGenClosure;
-// DefNew
-class ScanClosure;
-class FastScanClosure;
-class FilteringClosure;
-// MarkSweep
-class MarkAndPushClosure;
-class AdjustPointerClosure;
-// ParNew
-class ParScanWithBarrierClosure;
-class ParScanWithoutBarrierClosure;
-// CMS
-class MarkRefsIntoAndScanClosure;
-class ParMarkRefsIntoAndScanClosure;
-class PushAndMarkClosure;
-class ParPushAndMarkClosure;
-class PushOrMarkClosure;
-class ParPushOrMarkClosure;
-class CMSKeepAliveClosure;
-class CMSInnerParMarkAndPushClosure;
-// Misc
-class NoHeaderExtendedOopClosure;
// This macro applies an argument macro to all OopClosures for which we
// want specialized bodies of "oop_oop_iterate". The arguments to "f" are:
@@ -72,80 +54,38 @@
// This is split into several because of a Visual C++ 6.0 compiler bug
// where very long macros cause the compiler to crash
-#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(f) \
- f(ScanClosure,_nv) \
- f(FastScanClosure,_nv) \
- f(FilteringClosure,_nv)
-
-#if INCLUDE_ALL_GCS
-#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f) \
- f(ParScanWithBarrierClosure,_nv) \
- f(ParScanWithoutBarrierClosure,_nv)
-#else // INCLUDE_ALL_GCS
-#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f)
-#endif // INCLUDE_ALL_GCS
-
-#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(f) \
- f(NoHeaderExtendedOopClosure,_nv) \
- SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(f) \
- SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f)
-
-#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_MS(f) \
- f(MarkAndPushClosure,_nv) \
- f(AdjustPointerClosure,_nv)
+#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(f) \
+ f(NoHeaderExtendedOopClosure,_nv) \
+ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(f) \
+ ALL_GCS_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f))
-#if INCLUDE_ALL_GCS
-#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_CMS(f) \
- f(MarkRefsIntoAndScanClosure,_nv) \
- f(ParMarkRefsIntoAndScanClosure,_nv) \
- f(PushAndMarkClosure,_nv) \
- f(ParPushAndMarkClosure,_nv) \
- f(PushOrMarkClosure,_nv) \
- f(ParPushOrMarkClosure,_nv) \
- f(CMSKeepAliveClosure,_nv) \
- f(CMSInnerParMarkAndPushClosure,_nv)
-#endif
-
-#if INCLUDE_ALL_GCS
-#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) \
- SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_MS(f) \
- SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_CMS(f) \
- SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1(f) \
- SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1FULL(f)
-#else // INCLUDE_ALL_GCS
-#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) \
- SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_MS(f)
-#endif // INCLUDE_ALL_GCS
-
+#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) \
+ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_MS(f) \
+ ALL_GCS_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_CMS(f)) \
+ ALL_GCS_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1(f)) \
+ ALL_GCS_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1FULL(f))
// We separate these out, because sometime the general one has
// a different definition from the specialized ones, and sometimes it
// doesn't.
-#define ALL_OOP_OOP_ITERATE_CLOSURES_1(f) \
- f(ExtendedOopClosure,_v) \
+#define ALL_OOP_OOP_ITERATE_CLOSURES_1(f) \
+ f(ExtendedOopClosure,_v) \
SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(f)
-#define ALL_OOP_OOP_ITERATE_CLOSURES_2(f) \
+#define ALL_OOP_OOP_ITERATE_CLOSURES_2(f) \
SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f)
-#if INCLUDE_ALL_GCS
// This macro applies an argument macro to all OopClosures for which we
// want specialized bodies of a family of methods related to
// "par_oop_iterate". The arguments to f are the same as above.
// The "root_class" is the most general class to define; this may be
// "OopClosure" in some applications and "OopsInGenClosure" in others.
-#define SPECIALIZED_PAR_OOP_ITERATE_CLOSURES(f) \
- f(MarkRefsIntoAndScanClosure,_nv) \
- f(PushAndMarkClosure,_nv) \
- f(ParMarkRefsIntoAndScanClosure,_nv) \
- f(ParPushAndMarkClosure,_nv)
-#define ALL_PAR_OOP_ITERATE_CLOSURES(f) \
- f(ExtendedOopClosure,_v) \
- SPECIALIZED_PAR_OOP_ITERATE_CLOSURES(f)
-#endif // INCLUDE_ALL_GCS
+#define ALL_PAR_OOP_ITERATE_CLOSURES(f) \
+ f(ExtendedOopClosure,_v) \
+ ALL_GCS_ONLY(SPECIALIZED_PAR_OOP_ITERATE_CLOSURES(f))
// This macro applies an argument macro to all OopClosures for which we
// want specialized bodies of a family of methods related to
@@ -153,31 +93,19 @@
// The "root_class" is the most general class to define; this may be
// "OopClosure" in some applications and "OopsInGenClosure" in others.
-#define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_S(f) \
- f(ScanClosure,_nv) \
- f(FastScanClosure,_nv)
+#define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG(f) \
+ SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_S(f) \
+ ALL_GCS_ONLY(SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f))
-#if INCLUDE_ALL_GCS
-#define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f) \
- f(ParScanWithBarrierClosure,_nv) \
- f(ParScanWithoutBarrierClosure,_nv)
-#else // INCLUDE_ALL_GCS
-#define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f)
-#endif // INCLUDE_ALL_GCS
-
-#define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG(f) \
- SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_S(f) \
- SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f)
-
-#define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES(f) \
+#define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES(f) \
SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG(f)
// We separate these out, because sometime the general one has
// a different definition from the specialized ones, and sometimes it
// doesn't.
-#define ALL_SINCE_SAVE_MARKS_CLOSURES(f) \
- f(OopsInGenClosure,_v) \
+#define ALL_SINCE_SAVE_MARKS_CLOSURES(f) \
+ f(OopsInGenClosure,_v) \
SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES(f)
#endif // SHARE_VM_GC_SHARED_SPECIALIZED_OOP_CLOSURES_HPP
--- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,7 +23,6 @@
*/
#include "precompiled.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/threadLocalAllocBuffer.inline.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_GC_SHARED_VMSTRUCTS_GC_HPP
+#define SHARE_GC_SHARED_VMSTRUCTS_GC_HPP
+
+#include "gc/shared/cardGeneration.hpp"
+#include "gc/shared/cardTableRS.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/genCollectedHeap.hpp"
+#include "gc/shared/generation.hpp"
+#include "gc/shared/generationSpec.hpp"
+#include "gc/shared/oopStorage.hpp"
+#include "gc/shared/space.hpp"
+#include "gc/serial/defNewGeneration.hpp"
+#include "gc/serial/vmStructs_serial.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/cms/vmStructs_cms.hpp"
+#include "gc/g1/vmStructs_g1.hpp"
+#include "gc/parallel/vmStructs_parallelgc.hpp"
+#endif
+
+#define VM_STRUCTS_GC(nonstatic_field, \
+ volatile_nonstatic_field, \
+ static_field, \
+ unchecked_nonstatic_field) \
+ ALL_GCS_ONLY(VM_STRUCTS_CMSGC(nonstatic_field, \
+ volatile_nonstatic_field, \
+ static_field)) \
+ ALL_GCS_ONLY(VM_STRUCTS_G1GC(nonstatic_field, \
+ volatile_nonstatic_field, \
+ static_field)) \
+ ALL_GCS_ONLY(VM_STRUCTS_PARALLELGC(nonstatic_field, \
+ volatile_nonstatic_field, \
+ static_field)) \
+ VM_STRUCTS_SERIALGC(nonstatic_field, \
+ volatile_nonstatic_field, \
+ static_field) \
+ /**********************************************************************************/ \
+ /* Generation and Space hierarchies */ \
+ /**********************************************************************************/ \
+ \
+ unchecked_nonstatic_field(AgeTable, sizes, sizeof(AgeTable::sizes)) \
+ \
+ nonstatic_field(BarrierSet, _fake_rtti, BarrierSet::FakeRtti) \
+ \
+ nonstatic_field(BarrierSet::FakeRtti, _concrete_tag, BarrierSet::Name) \
+ \
+ nonstatic_field(BlockOffsetTable, _bottom, HeapWord*) \
+ nonstatic_field(BlockOffsetTable, _end, HeapWord*) \
+ \
+ nonstatic_field(BlockOffsetSharedArray, _reserved, MemRegion) \
+ nonstatic_field(BlockOffsetSharedArray, _end, HeapWord*) \
+ nonstatic_field(BlockOffsetSharedArray, _vs, VirtualSpace) \
+ nonstatic_field(BlockOffsetSharedArray, _offset_array, u_char*) \
+ \
+ nonstatic_field(BlockOffsetArray, _array, BlockOffsetSharedArray*) \
+ nonstatic_field(BlockOffsetArray, _sp, Space*) \
+ nonstatic_field(BlockOffsetArrayContigSpace, _next_offset_threshold, HeapWord*) \
+ nonstatic_field(BlockOffsetArrayContigSpace, _next_offset_index, size_t) \
+ \
+ nonstatic_field(BlockOffsetArrayNonContigSpace, _unallocated_block, HeapWord*) \
+ \
+ nonstatic_field(CardGeneration, _rs, CardTableRS*) \
+ nonstatic_field(CardGeneration, _bts, BlockOffsetSharedArray*) \
+ nonstatic_field(CardGeneration, _shrink_factor, size_t) \
+ nonstatic_field(CardGeneration, _capacity_at_prologue, size_t) \
+ nonstatic_field(CardGeneration, _used_at_prologue, size_t) \
+ \
+ nonstatic_field(CardTable, _whole_heap, const MemRegion) \
+ nonstatic_field(CardTable, _guard_index, const size_t) \
+ nonstatic_field(CardTable, _last_valid_index, const size_t) \
+ nonstatic_field(CardTable, _page_size, const size_t) \
+ nonstatic_field(CardTable, _byte_map_size, const size_t) \
+ nonstatic_field(CardTable, _byte_map, jbyte*) \
+ nonstatic_field(CardTable, _cur_covered_regions, int) \
+ nonstatic_field(CardTable, _covered, MemRegion*) \
+ nonstatic_field(CardTable, _committed, MemRegion*) \
+ nonstatic_field(CardTable, _guard_region, MemRegion) \
+ nonstatic_field(CardTable, _byte_map_base, jbyte*) \
+ nonstatic_field(CardTableBarrierSet, _defer_initial_card_mark, bool) \
+ nonstatic_field(CardTableBarrierSet, _card_table, CardTable*) \
+ \
+ nonstatic_field(CollectedHeap, _reserved, MemRegion) \
+ nonstatic_field(CollectedHeap, _is_gc_active, bool) \
+ nonstatic_field(CollectedHeap, _total_collections, unsigned int) \
+ \
+ nonstatic_field(CompactibleSpace, _compaction_top, HeapWord*) \
+ nonstatic_field(CompactibleSpace, _first_dead, HeapWord*) \
+ nonstatic_field(CompactibleSpace, _end_of_live, HeapWord*) \
+ \
+ nonstatic_field(ContiguousSpace, _top, HeapWord*) \
+ nonstatic_field(ContiguousSpace, _concurrent_iteration_safe_limit, HeapWord*) \
+ nonstatic_field(ContiguousSpace, _saved_mark_word, HeapWord*) \
+ \
+ nonstatic_field(DefNewGeneration, _old_gen, Generation*) \
+ nonstatic_field(DefNewGeneration, _tenuring_threshold, uint) \
+ nonstatic_field(DefNewGeneration, _age_table, AgeTable) \
+ nonstatic_field(DefNewGeneration, _eden_space, ContiguousSpace*) \
+ nonstatic_field(DefNewGeneration, _from_space, ContiguousSpace*) \
+ nonstatic_field(DefNewGeneration, _to_space, ContiguousSpace*) \
+ \
+ nonstatic_field(Generation, _reserved, MemRegion) \
+ nonstatic_field(Generation, _virtual_space, VirtualSpace) \
+ nonstatic_field(Generation, _stat_record, Generation::StatRecord) \
+ \
+ nonstatic_field(Generation::StatRecord, invocations, int) \
+ nonstatic_field(Generation::StatRecord, accumulated_time, elapsedTimer) \
+ \
+ nonstatic_field(GenerationSpec, _name, Generation::Name) \
+ nonstatic_field(GenerationSpec, _init_size, size_t) \
+ nonstatic_field(GenerationSpec, _max_size, size_t) \
+ \
+ nonstatic_field(GenCollectedHeap, _young_gen, Generation*) \
+ nonstatic_field(GenCollectedHeap, _old_gen, Generation*) \
+ nonstatic_field(GenCollectedHeap, _young_gen_spec, GenerationSpec*) \
+ nonstatic_field(GenCollectedHeap, _old_gen_spec, GenerationSpec*) \
+ \
+ nonstatic_field(HeapWord, i, char*) \
+ \
+ nonstatic_field(MemRegion, _start, HeapWord*) \
+ nonstatic_field(MemRegion, _word_size, size_t) \
+ \
+ nonstatic_field(OffsetTableContigSpace, _offsets, BlockOffsetArray) \
+ \
+ nonstatic_field(Space, _bottom, HeapWord*) \
+ nonstatic_field(Space, _end, HeapWord*)
+
+#define VM_TYPES_GC(declare_type, \
+ declare_toplevel_type, \
+ declare_integer_type) \
+ ALL_GCS_ONLY(VM_TYPES_CMSGC(declare_type, \
+ declare_toplevel_type, \
+ declare_integer_type)) \
+ ALL_GCS_ONLY(VM_TYPES_G1GC(declare_type, \
+ declare_toplevel_type, \
+ declare_integer_type)) \
+ ALL_GCS_ONLY(VM_TYPES_PARALLELGC(declare_type, \
+ declare_toplevel_type, \
+ declare_integer_type)) \
+ VM_TYPES_SERIALGC(declare_type, \
+ declare_toplevel_type, \
+ declare_integer_type) \
+ /******************************************/ \
+ /* Generation and space hierarchies */ \
+ /* (needed for run-time type information) */ \
+ /******************************************/ \
+ \
+ declare_toplevel_type(CollectedHeap) \
+ declare_type(GenCollectedHeap, CollectedHeap) \
+ declare_toplevel_type(Generation) \
+ declare_type(DefNewGeneration, Generation) \
+ declare_type(CardGeneration, Generation) \
+ declare_toplevel_type(Space) \
+ declare_type(CompactibleSpace, Space) \
+ declare_type(ContiguousSpace, CompactibleSpace) \
+ declare_type(OffsetTableContigSpace, ContiguousSpace) \
+ declare_toplevel_type(BarrierSet) \
+ declare_type(ModRefBarrierSet, BarrierSet) \
+ declare_type(CardTableBarrierSet, ModRefBarrierSet) \
+ declare_toplevel_type(CardTable) \
+ declare_type(CardTableRS, CardTable) \
+ declare_toplevel_type(BarrierSet::Name) \
+ declare_toplevel_type(BlockOffsetSharedArray) \
+ declare_toplevel_type(BlockOffsetTable) \
+ declare_type(BlockOffsetArray, BlockOffsetTable) \
+ declare_type(BlockOffsetArrayContigSpace, BlockOffsetArray) \
+ declare_type(BlockOffsetArrayNonContigSpace, BlockOffsetArray) \
+ \
+ /* Miscellaneous other GC types */ \
+ \
+ declare_toplevel_type(AgeTable) \
+ declare_toplevel_type(Generation::StatRecord) \
+ declare_toplevel_type(GenerationSpec) \
+ declare_toplevel_type(HeapWord) \
+ declare_toplevel_type(MemRegion) \
+ declare_toplevel_type(ThreadLocalAllocBuffer) \
+ declare_toplevel_type(VirtualSpace) \
+ \
+ /* Pointers to Garbage Collection types */ \
+ \
+ declare_toplevel_type(BarrierSet*) \
+ declare_toplevel_type(BlockOffsetSharedArray*) \
+ declare_toplevel_type(CardTable*) \
+ declare_toplevel_type(CardTable*const) \
+ declare_toplevel_type(CardTableRS*) \
+ declare_toplevel_type(CardTableBarrierSet*) \
+ declare_toplevel_type(CardTableBarrierSet**) \
+ declare_toplevel_type(CollectedHeap*) \
+ declare_toplevel_type(ContiguousSpace*) \
+ declare_toplevel_type(DefNewGeneration*) \
+ declare_toplevel_type(GenCollectedHeap*) \
+ declare_toplevel_type(Generation*) \
+ declare_toplevel_type(GenerationSpec**) \
+ declare_toplevel_type(HeapWord*) \
+ declare_toplevel_type(HeapWord* volatile) \
+ declare_toplevel_type(MemRegion*) \
+ declare_toplevel_type(OffsetTableContigSpace*) \
+ declare_toplevel_type(Space*) \
+ declare_toplevel_type(ThreadLocalAllocBuffer*) \
+ \
+ declare_toplevel_type(BarrierSet::FakeRtti)
+
+#define VM_INT_CONSTANTS_GC(declare_constant, \
+ declare_constant_with_value) \
+ ALL_GCS_ONLY(VM_INT_CONSTANTS_CMSGC(declare_constant, \
+ declare_constant_with_value)) \
+ ALL_GCS_ONLY(VM_INT_CONSTANTS_G1GC(declare_constant, \
+ declare_constant_with_value)) \
+ ALL_GCS_ONLY(VM_INT_CONSTANTS_PARALLELGC(declare_constant, \
+ declare_constant_with_value)) \
+ VM_INT_CONSTANTS_SERIALGC(declare_constant, \
+ declare_constant_with_value) \
+ \
+ /********************************************/ \
+ /* Generation and Space Hierarchy Constants */ \
+ /********************************************/ \
+ \
+ declare_constant(AgeTable::table_size) \
+ \
+ declare_constant(BarrierSet::ModRef) \
+ declare_constant(BarrierSet::CardTableBarrierSet) \
+ \
+ declare_constant(BOTConstants::LogN) \
+ declare_constant(BOTConstants::LogN_words) \
+ declare_constant(BOTConstants::N_bytes) \
+ declare_constant(BOTConstants::N_words) \
+ declare_constant(BOTConstants::LogBase) \
+ declare_constant(BOTConstants::Base) \
+ declare_constant(BOTConstants::N_powers) \
+ \
+ declare_constant(CardTable::clean_card) \
+ declare_constant(CardTable::last_card) \
+ declare_constant(CardTable::dirty_card) \
+ declare_constant(CardTable::Precise) \
+ declare_constant(CardTable::ObjHeadPreciseArray) \
+ declare_constant(CardTable::card_shift) \
+ declare_constant(CardTable::card_size) \
+ declare_constant(CardTable::card_size_in_words) \
+ \
+ declare_constant(CardTableRS::youngergen_card) \
+ \
+ declare_constant(CollectedHeap::Serial) \
+ declare_constant(CollectedHeap::Parallel) \
+ declare_constant(CollectedHeap::CMS) \
+ declare_constant(CollectedHeap::G1) \
+ \
+ /* constants from Generation::Name enum */ \
+ \
+ declare_constant(Generation::DefNew) \
+ declare_constant(Generation::MarkSweepCompact) \
+ declare_constant(Generation::Other) \
+ \
+ declare_constant(Generation::LogOfGenGrain) \
+ declare_constant(Generation::GenGrain) \
+
+
+#endif // SHARE_GC_SHARED_VMSTRUCTS_GC_HPP
--- a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -689,7 +689,7 @@
if (hash != markOopDesc::no_hash) {
header = header->copy_set_hash(hash);
}
- if (Atomic::cmpxchg(header, rcvr->mark_addr(), mark) == mark) {
+ if (rcvr->cas_set_mark(header, mark) == mark) {
if (PrintBiasedLockingStatistics)
(*BiasedLocking::revoked_lock_entry_count_addr())++;
}
@@ -699,7 +699,7 @@
if (hash != markOopDesc::no_hash) {
new_header = new_header->copy_set_hash(hash);
}
- if (Atomic::cmpxchg(new_header, rcvr->mark_addr(), mark) == mark) {
+ if (rcvr->cas_set_mark(new_header, mark) == mark) {
if (PrintBiasedLockingStatistics) {
(* BiasedLocking::rebiased_lock_entry_count_addr())++;
}
@@ -718,7 +718,7 @@
markOop new_header = (markOop) ((uintptr_t) header | thread_ident);
// Debugging hint.
DEBUG_ONLY(mon->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);)
- if (Atomic::cmpxchg(new_header, rcvr->mark_addr(), header) == header) {
+ if (rcvr->cas_set_mark(new_header, header) == header) {
if (PrintBiasedLockingStatistics) {
(* BiasedLocking::anonymously_biased_lock_entry_count_addr())++;
}
@@ -734,7 +734,7 @@
markOop displaced = rcvr->mark()->set_unlocked();
mon->lock()->set_displaced_header(displaced);
bool call_vm = UseHeavyMonitors;
- if (call_vm || Atomic::cmpxchg((markOop)mon, rcvr->mark_addr(), displaced) != displaced) {
+ if (call_vm || rcvr->cas_set_mark((markOop)mon, displaced) != displaced) {
// Is it simple recursive case?
if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) {
mon->lock()->set_displaced_header(NULL);
@@ -875,7 +875,7 @@
if (hash != markOopDesc::no_hash) {
header = header->copy_set_hash(hash);
}
- if (Atomic::cmpxchg(header, lockee->mark_addr(), mark) == mark) {
+ if (lockee->cas_set_mark(header, mark) == mark) {
if (PrintBiasedLockingStatistics) {
(*BiasedLocking::revoked_lock_entry_count_addr())++;
}
@@ -886,7 +886,7 @@
if (hash != markOopDesc::no_hash) {
new_header = new_header->copy_set_hash(hash);
}
- if (Atomic::cmpxchg(new_header, lockee->mark_addr(), mark) == mark) {
+ if (lockee->cas_set_mark(new_header, mark) == mark) {
if (PrintBiasedLockingStatistics) {
(* BiasedLocking::rebiased_lock_entry_count_addr())++;
}
@@ -904,7 +904,7 @@
markOop new_header = (markOop) ((uintptr_t) header | thread_ident);
// debugging hint
DEBUG_ONLY(entry->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);)
- if (Atomic::cmpxchg(new_header, lockee->mark_addr(), header) == header) {
+ if (lockee->cas_set_mark(new_header, header) == header) {
if (PrintBiasedLockingStatistics) {
(* BiasedLocking::anonymously_biased_lock_entry_count_addr())++;
}
@@ -920,7 +920,7 @@
markOop displaced = lockee->mark()->set_unlocked();
entry->lock()->set_displaced_header(displaced);
bool call_vm = UseHeavyMonitors;
- if (call_vm || Atomic::cmpxchg((markOop)entry, lockee->mark_addr(), displaced) != displaced) {
+ if (call_vm || lockee->cas_set_mark((markOop)entry, displaced) != displaced) {
// Is it simple recursive case?
if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) {
entry->lock()->set_displaced_header(NULL);
@@ -1816,7 +1816,7 @@
if (hash != markOopDesc::no_hash) {
header = header->copy_set_hash(hash);
}
- if (Atomic::cmpxchg(header, lockee->mark_addr(), mark) == mark) {
+ if (lockee->cas_set_mark(header, mark) == mark) {
if (PrintBiasedLockingStatistics)
(*BiasedLocking::revoked_lock_entry_count_addr())++;
}
@@ -1827,7 +1827,7 @@
if (hash != markOopDesc::no_hash) {
new_header = new_header->copy_set_hash(hash);
}
- if (Atomic::cmpxchg(new_header, lockee->mark_addr(), mark) == mark) {
+ if (lockee->cas_set_mark(new_header, mark) == mark) {
if (PrintBiasedLockingStatistics)
(* BiasedLocking::rebiased_lock_entry_count_addr())++;
}
@@ -1847,7 +1847,7 @@
markOop new_header = (markOop) ((uintptr_t) header | thread_ident);
// debugging hint
DEBUG_ONLY(entry->lock()->set_displaced_header((markOop) (uintptr_t) 0xdeaddead);)
- if (Atomic::cmpxchg(new_header, lockee->mark_addr(), header) == header) {
+ if (lockee->cas_set_mark(new_header, header) == header) {
if (PrintBiasedLockingStatistics)
(* BiasedLocking::anonymously_biased_lock_entry_count_addr())++;
}
@@ -1863,7 +1863,7 @@
markOop displaced = lockee->mark()->set_unlocked();
entry->lock()->set_displaced_header(displaced);
bool call_vm = UseHeavyMonitors;
- if (call_vm || Atomic::cmpxchg((markOop)entry, lockee->mark_addr(), displaced) != displaced) {
+ if (call_vm || lockee->cas_set_mark((markOop)entry, displaced) != displaced) {
// Is it simple recursive case?
if (!call_vm && THREAD->is_lock_owned((address) displaced->clear_lock_bits())) {
entry->lock()->set_displaced_header(NULL);
--- a/src/hotspot/share/interpreter/bytecodes.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/interpreter/bytecodes.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -45,7 +45,7 @@
s_char Bytecodes::_depth [Bytecodes::number_of_codes];
u_char Bytecodes::_lengths [Bytecodes::number_of_codes];
Bytecodes::Code Bytecodes::_java_code [Bytecodes::number_of_codes];
-u_short Bytecodes::_flags [(1<<BitsPerByte)*2];
+unsigned short Bytecodes::_flags [(1<<BitsPerByte)*2];
#ifdef ASSERT
bool Bytecodes::check_method(const Method* method, address bcp) {
--- a/src/hotspot/share/interpreter/templateTable.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/interpreter/templateTable.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/barrierSet.hpp"
#include "interpreter/interp_masm.hpp"
#include "interpreter/templateTable.hpp"
#include "runtime/timerTrace.hpp"
@@ -247,7 +247,7 @@
// Initialize table
TraceTime timer("TemplateTable initialization", TRACETIME_LOG(Info, startuptime));
- _bs = Universe::heap()->barrier_set();
+ _bs = BarrierSet::barrier_set();
// For better readability
const char _ = ' ';
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* 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/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,6 +23,7 @@
// no precompiled headers
#include "ci/ciUtilities.hpp"
+#include "gc/shared/barrierSet.hpp"
#include "memory/oopFactory.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "jvmci/jvmciRuntime.hpp"
@@ -120,7 +121,7 @@
symbol_init = (address) vmSymbols::object_initializer_name();
symbol_clinit = (address) vmSymbols::class_initializer_name();
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
if (bs->is_a(BarrierSet::CardTableBarrierSet)) {
jbyte* base = ci_card_table_address();
assert(base != NULL, "unexpected byte_map_base");
--- a/src/hotspot/share/jvmci/jvmciRuntime.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -50,6 +50,9 @@
#include "utilities/debug.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/macros.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1ThreadLocalData.hpp"
+#endif // INCLUDE_ALL_GCS
#if defined(_MSC_VER)
#define strtoll _strtoi64
@@ -454,11 +457,15 @@
JRT_END
JRT_LEAF(void, JVMCIRuntime::write_barrier_pre(JavaThread* thread, oopDesc* obj))
- thread->satb_mark_queue().enqueue(obj);
+#if INCLUDE_ALL_GCS
+ G1ThreadLocalData::satb_mark_queue(thread).enqueue(obj);
+#endif // INCLUDE_ALL_GCS
JRT_END
JRT_LEAF(void, JVMCIRuntime::write_barrier_post(JavaThread* thread, void* card_addr))
- thread->dirty_card_queue().enqueue(card_addr);
+#if INCLUDE_ALL_GCS
+ G1ThreadLocalData::dirty_card_queue(thread).enqueue(card_addr);
+#endif // INCLUDE_ALL_GCS
JRT_END
JRT_LEAF(jboolean, JVMCIRuntime::validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child))
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,6 +44,7 @@
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1CardTable.hpp"
#include "gc/g1/heapRegion.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
#endif
#define VM_STRUCTS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field) \
@@ -172,8 +173,6 @@
volatile_nonstatic_field(JavaThread, _exception_pc, address) \
volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \
nonstatic_field(JavaThread, _osthread, OSThread*) \
- nonstatic_field(JavaThread, _satb_mark_queue, SATBMarkQueue) \
- nonstatic_field(JavaThread, _dirty_card_queue, DirtyCardQueue) \
nonstatic_field(JavaThread, _pending_deoptimization, int) \
nonstatic_field(JavaThread, _pending_failed_speculation, oop) \
nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \
@@ -515,9 +514,6 @@
declare_constant(Deoptimization::Reason_jsr_mismatch) \
declare_constant(Deoptimization::Reason_LIMIT) \
\
- declare_constant_with_value("dirtyCardQueueBufferOffset", in_bytes(DirtyCardQueue::byte_offset_of_buf())) \
- declare_constant_with_value("dirtyCardQueueIndexOffset", in_bytes(DirtyCardQueue::byte_offset_of_index())) \
- \
declare_constant(FieldInfo::access_flags_offset) \
declare_constant(FieldInfo::name_index_offset) \
declare_constant(FieldInfo::signature_index_offset) \
@@ -573,10 +569,6 @@
declare_constant(ReceiverTypeData::receiver0_offset) \
declare_constant(ReceiverTypeData::count0_offset) \
\
- declare_constant_with_value("satbMarkQueueBufferOffset", in_bytes(SATBMarkQueue::byte_offset_of_buf())) \
- declare_constant_with_value("satbMarkQueueIndexOffset", in_bytes(SATBMarkQueue::byte_offset_of_index())) \
- declare_constant_with_value("satbMarkQueueActiveOffset", in_bytes(SATBMarkQueue::byte_offset_of_active())) \
- \
declare_constant(vmIntrinsics::_invokeBasic) \
declare_constant(vmIntrinsics::_linkToVirtual) \
declare_constant(vmIntrinsics::_linkToStatic) \
@@ -641,8 +633,8 @@
declare_function(JVMCIRuntime::log_printf) \
declare_function(JVMCIRuntime::vm_error) \
declare_function(JVMCIRuntime::load_and_clear_exception) \
- declare_function(JVMCIRuntime::write_barrier_pre) \
- declare_function(JVMCIRuntime::write_barrier_post) \
+ ALL_GCS_ONLY(declare_function(JVMCIRuntime::write_barrier_pre)) \
+ ALL_GCS_ONLY(declare_function(JVMCIRuntime::write_barrier_post)) \
declare_function(JVMCIRuntime::validate_object) \
\
declare_function(JVMCIRuntime::test_deoptimize_call_int)
@@ -650,11 +642,16 @@
#if INCLUDE_ALL_GCS
-#define VM_STRUCTS_G1(nonstatic_field, static_field) \
+#define VM_STRUCTS_JVMCI_G1GC(nonstatic_field, static_field) \
static_field(HeapRegion, LogOfHRGrainBytes, int)
-#define VM_INT_CONSTANTS_G1(declare_constant, declare_constant_with_value, declare_preprocessor_constant) \
- declare_constant_with_value("G1CardTable::g1_young_gen", G1CardTable::g1_young_card_val())
+#define VM_INT_CONSTANTS_JVMCI_G1GC(declare_constant, declare_constant_with_value, declare_preprocessor_constant) \
+ declare_constant_with_value("G1CardTable::g1_young_gen", G1CardTable::g1_young_card_val()) \
+ declare_constant_with_value("G1ThreadLocalData::satb_mark_queue_active_offset", in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())) \
+ declare_constant_with_value("G1ThreadLocalData::satb_mark_queue_index_offset", in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())) \
+ declare_constant_with_value("G1ThreadLocalData::satb_mark_queue_buffer_offset", in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())) \
+ declare_constant_with_value("G1ThreadLocalData::dirty_card_queue_index_offset", in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())) \
+ declare_constant_with_value("G1ThreadLocalData::dirty_card_queue_buffer_offset", in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()))
#endif // INCLUDE_ALL_GCS
@@ -873,8 +870,8 @@
GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY)
#if INCLUDE_ALL_GCS
- VM_STRUCTS_G1(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
- GENERATE_STATIC_VM_STRUCT_ENTRY)
+ VM_STRUCTS_JVMCI_G1GC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
+ GENERATE_STATIC_VM_STRUCT_ENTRY)
#endif
GENERATE_VM_STRUCT_LAST_ENTRY()
@@ -925,9 +922,9 @@
GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
#if INCLUDE_ALL_GCS
- VM_INT_CONSTANTS_G1(GENERATE_VM_INT_CONSTANT_ENTRY,
- GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY,
- GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
+ VM_INT_CONSTANTS_JVMCI_G1GC(GENERATE_VM_INT_CONSTANT_ENTRY,
+ GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY,
+ GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
#endif
GENERATE_VM_INT_CONSTANT_LAST_ENTRY()
--- a/src/hotspot/share/logging/logHandle.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/logging/logHandle.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,6 +43,10 @@
return _tagset->is_level(level);
}
+ LogTagSet* tagset() const {
+ return _tagset;
+ }
+
#define LOG_LEVEL(level, name) ATTRIBUTE_PRINTF(2, 0) \
LogHandle& v##name(const char* fmt, va_list args) { \
_tagset->vwrite(LogLevel::level, fmt, args); \
--- a/src/hotspot/share/logging/logTag.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/logging/logTag.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -112,6 +112,7 @@
LOG_TAG(perf) \
LOG_TAG(phases) \
LOG_TAG(plab) \
+ LOG_TAG(preview) /* Trace loading of preview feature types */ \
LOG_TAG(promotion) \
LOG_TAG(preorder) /* Trace all classes loaded in order referenced (not loaded) */ \
LOG_TAG(protectiondomain) /* "Trace protection domain verification" */ \
--- a/src/hotspot/share/memory/allocation.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/memory/allocation.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,7 +23,6 @@
*/
#include "precompiled.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/arena.hpp"
--- a/src/hotspot/share/memory/arena.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/memory/arena.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,7 +23,6 @@
*/
#include "precompiled.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/metaspaceShared.hpp"
--- a/src/hotspot/share/memory/binaryTreeDictionary.cpp Tue Apr 17 08:54:17 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1429 +0,0 @@
-/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
- * 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/cms/allocationStats.hpp"
-#include "gc/shared/spaceDecorator.hpp"
-#include "logging/log.hpp"
-#include "logging/logStream.hpp"
-#include "memory/binaryTreeDictionary.hpp"
-#include "memory/freeList.hpp"
-#include "memory/metachunk.hpp"
-#include "memory/resourceArea.hpp"
-#include "runtime/globals.hpp"
-#include "utilities/macros.hpp"
-#include "utilities/ostream.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/cms/adaptiveFreeList.hpp"
-#include "gc/cms/freeChunk.hpp"
-#endif // INCLUDE_ALL_GCS
-
-////////////////////////////////////////////////////////////////////////////////
-// A binary tree based search structure for free blocks.
-// This is currently used in the Concurrent Mark&Sweep implementation.
-////////////////////////////////////////////////////////////////////////////////
-
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>* TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(Chunk_t* fc) {
- // Do some assertion checking here.
- return (TreeChunk<Chunk_t, FreeList_t>*) fc;
-}
-
-template <class Chunk_t, class FreeList_t>
-void TreeChunk<Chunk_t, FreeList_t>::verify_tree_chunk_list() const {
- TreeChunk<Chunk_t, FreeList_t>* nextTC = (TreeChunk<Chunk_t, FreeList_t>*)next();
- if (prev() != NULL) { // interior list node shouldn't have tree fields
- guarantee(embedded_list()->parent() == NULL && embedded_list()->left() == NULL &&
- embedded_list()->right() == NULL, "should be clear");
- }
- if (nextTC != NULL) {
- guarantee(as_TreeChunk(nextTC->prev()) == this, "broken chain");
- guarantee(nextTC->size() == size(), "wrong size");
- nextTC->verify_tree_chunk_list();
- }
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>::TreeList() : _parent(NULL),
- _left(NULL), _right(NULL) {}
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>*
-TreeList<Chunk_t, FreeList_t>::as_TreeList(TreeChunk<Chunk_t,FreeList_t>* tc) {
- // This first free chunk in the list will be the tree list.
- assert((tc->size() >= (TreeChunk<Chunk_t, FreeList_t>::min_size())),
- "Chunk is too small for a TreeChunk");
- TreeList<Chunk_t, FreeList_t>* tl = tc->embedded_list();
- tl->initialize();
- tc->set_list(tl);
- tl->set_size(tc->size());
- tl->link_head(tc);
- tl->link_tail(tc);
- tl->set_count(1);
- assert(tl->parent() == NULL, "Should be clear");
- return tl;
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>*
-TreeList<Chunk_t, FreeList_t>::as_TreeList(HeapWord* addr, size_t size) {
- TreeChunk<Chunk_t, FreeList_t>* tc = (TreeChunk<Chunk_t, FreeList_t>*) addr;
- assert((size >= TreeChunk<Chunk_t, FreeList_t>::min_size()),
- "Chunk is too small for a TreeChunk");
- // The space will have been mangled initially but
- // is not remangled when a Chunk_t is returned to the free list
- // (since it is used to maintain the chunk on the free list).
- tc->assert_is_mangled();
- tc->set_size(size);
- tc->link_prev(NULL);
- tc->link_next(NULL);
- TreeList<Chunk_t, FreeList_t>* tl = TreeList<Chunk_t, FreeList_t>::as_TreeList(tc);
- return tl;
-}
-
-
-#if INCLUDE_ALL_GCS
-// Specialize for AdaptiveFreeList which tries to avoid
-// splitting a chunk of a size that is under populated in favor of
-// an over populated size. The general get_better_list() just returns
-// the current list.
-template <>
-TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >*
-TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >::get_better_list(
- BinaryTreeDictionary<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* dictionary) {
- // A candidate chunk has been found. If it is already under
- // populated, get a chunk associated with the hint for this
- // chunk.
-
- TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* curTL = this;
- if (curTL->surplus() <= 0) {
- /* Use the hint to find a size with a surplus, and reset the hint. */
- TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
- while (hintTL->hint() != 0) {
- assert(hintTL->hint() > hintTL->size(),
- "hint points in the wrong direction");
- hintTL = dictionary->find_list(hintTL->hint());
- assert(curTL != hintTL, "Infinite loop");
- if (hintTL == NULL ||
- hintTL == curTL /* Should not happen but protect against it */ ) {
- // No useful hint. Set the hint to NULL and go on.
- curTL->set_hint(0);
- break;
- }
- assert(hintTL->size() > curTL->size(), "hint is inconsistent");
- if (hintTL->surplus() > 0) {
- // The hint led to a list that has a surplus. Use it.
- // Set the hint for the candidate to an overpopulated
- // size.
- curTL->set_hint(hintTL->size());
- // Change the candidate.
- curTL = hintTL;
- break;
- }
- }
- }
- return curTL;
-}
-#endif // INCLUDE_ALL_GCS
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>*
-TreeList<Chunk_t, FreeList_t>::get_better_list(
- BinaryTreeDictionary<Chunk_t, FreeList_t>* dictionary) {
- return this;
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::remove_chunk_replace_if_needed(TreeChunk<Chunk_t, FreeList_t>* tc) {
-
- TreeList<Chunk_t, FreeList_t>* retTL = this;
- Chunk_t* list = head();
- assert(!list || list != list->next(), "Chunk on list twice");
- assert(tc != NULL, "Chunk being removed is NULL");
- assert(parent() == NULL || this == parent()->left() ||
- this == parent()->right(), "list is inconsistent");
- assert(tc->is_free(), "Header is not marked correctly");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-
- Chunk_t* prevFC = tc->prev();
- TreeChunk<Chunk_t, FreeList_t>* nextTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(tc->next());
- assert(list != NULL, "should have at least the target chunk");
-
- // Is this the first item on the list?
- if (tc == list) {
- // The "getChunk..." functions for a TreeList<Chunk_t, FreeList_t> will not return the
- // first chunk in the list unless it is the last chunk in the list
- // because the first chunk is also acting as the tree node.
- // When coalescing happens, however, the first chunk in the a tree
- // list can be the start of a free range. Free ranges are removed
- // from the free lists so that they are not available to be
- // allocated when the sweeper yields (giving up the free list lock)
- // to allow mutator activity. If this chunk is the first in the
- // list and is not the last in the list, do the work to copy the
- // TreeList<Chunk_t, FreeList_t> from the first chunk to the next chunk and update all
- // the TreeList<Chunk_t, FreeList_t> pointers in the chunks in the list.
- if (nextTC == NULL) {
- assert(prevFC == NULL, "Not last chunk in the list");
- set_tail(NULL);
- set_head(NULL);
- } else {
- // copy embedded list.
- nextTC->set_embedded_list(tc->embedded_list());
- retTL = nextTC->embedded_list();
- // Fix the pointer to the list in each chunk in the list.
- // This can be slow for a long list. Consider having
- // an option that does not allow the first chunk on the
- // list to be coalesced.
- for (TreeChunk<Chunk_t, FreeList_t>* curTC = nextTC; curTC != NULL;
- curTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(curTC->next())) {
- curTC->set_list(retTL);
- }
- // Fix the parent to point to the new TreeList<Chunk_t, FreeList_t>.
- if (retTL->parent() != NULL) {
- if (this == retTL->parent()->left()) {
- retTL->parent()->set_left(retTL);
- } else {
- assert(this == retTL->parent()->right(), "Parent is incorrect");
- retTL->parent()->set_right(retTL);
- }
- }
- // Fix the children's parent pointers to point to the
- // new list.
- assert(right() == retTL->right(), "Should have been copied");
- if (retTL->right() != NULL) {
- retTL->right()->set_parent(retTL);
- }
- assert(left() == retTL->left(), "Should have been copied");
- if (retTL->left() != NULL) {
- retTL->left()->set_parent(retTL);
- }
- retTL->link_head(nextTC);
- assert(nextTC->is_free(), "Should be a free chunk");
- }
- } else {
- if (nextTC == NULL) {
- // Removing chunk at tail of list
- this->link_tail(prevFC);
- }
- // Chunk is interior to the list
- prevFC->link_after(nextTC);
- }
-
- // Below this point the embedded TreeList<Chunk_t, FreeList_t> being used for the
- // tree node may have changed. Don't use "this"
- // TreeList<Chunk_t, FreeList_t>*.
- // chunk should still be a free chunk (bit set in _prev)
- assert(!retTL->head() || retTL->size() == retTL->head()->size(),
- "Wrong sized chunk in list");
- debug_only(
- tc->link_prev(NULL);
- tc->link_next(NULL);
- tc->set_list(NULL);
- bool prev_found = false;
- bool next_found = false;
- for (Chunk_t* curFC = retTL->head();
- curFC != NULL; curFC = curFC->next()) {
- assert(curFC != tc, "Chunk is still in list");
- if (curFC == prevFC) {
- prev_found = true;
- }
- if (curFC == nextTC) {
- next_found = true;
- }
- }
- assert(prevFC == NULL || prev_found, "Chunk was lost from list");
- assert(nextTC == NULL || next_found, "Chunk was lost from list");
- assert(retTL->parent() == NULL ||
- retTL == retTL->parent()->left() ||
- retTL == retTL->parent()->right(),
- "list is inconsistent");
- )
- retTL->decrement_count();
-
- assert(tc->is_free(), "Should still be a free chunk");
- assert(retTL->head() == NULL || retTL->head()->prev() == NULL,
- "list invariant");
- assert(retTL->tail() == NULL || retTL->tail()->next() == NULL,
- "list invariant");
- return retTL;
-}
-
-template <class Chunk_t, class FreeList_t>
-void TreeList<Chunk_t, FreeList_t>::return_chunk_at_tail(TreeChunk<Chunk_t, FreeList_t>* chunk) {
- assert(chunk != NULL, "returning NULL chunk");
- assert(chunk->list() == this, "list should be set for chunk");
- assert(tail() != NULL, "The tree list is embedded in the first chunk");
- // which means that the list can never be empty.
- assert(!this->verify_chunk_in_free_list(chunk), "Double entry");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-
- Chunk_t* fc = tail();
- fc->link_after(chunk);
- this->link_tail(chunk);
-
- assert(!tail() || size() == tail()->size(), "Wrong sized chunk in list");
- FreeList_t::increment_count();
- debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-}
-
-// Add this chunk at the head of the list. "At the head of the list"
-// is defined to be after the chunk pointer to by head(). This is
-// because the TreeList<Chunk_t, FreeList_t> is embedded in the first TreeChunk<Chunk_t, FreeList_t> in the
-// list. See the definition of TreeChunk<Chunk_t, FreeList_t>.
-template <class Chunk_t, class FreeList_t>
-void TreeList<Chunk_t, FreeList_t>::return_chunk_at_head(TreeChunk<Chunk_t, FreeList_t>* chunk) {
- assert(chunk->list() == this, "list should be set for chunk");
- assert(head() != NULL, "The tree list is embedded in the first chunk");
- assert(chunk != NULL, "returning NULL chunk");
- assert(!this->verify_chunk_in_free_list(chunk), "Double entry");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-
- Chunk_t* fc = head()->next();
- if (fc != NULL) {
- chunk->link_after(fc);
- } else {
- assert(tail() == NULL, "List is inconsistent");
- this->link_tail(chunk);
- }
- head()->link_after(chunk);
- assert(!head() || size() == head()->size(), "Wrong sized chunk in list");
- FreeList_t::increment_count();
- debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-}
-
-template <class Chunk_t, class FreeList_t>
-void TreeChunk<Chunk_t, FreeList_t>::assert_is_mangled() const {
- assert((ZapUnusedHeapArea &&
- SpaceMangler::is_mangled((HeapWord*) Chunk_t::size_addr()) &&
- SpaceMangler::is_mangled((HeapWord*) Chunk_t::prev_addr()) &&
- SpaceMangler::is_mangled((HeapWord*) Chunk_t::next_addr())) ||
- (size() == 0 && prev() == NULL && next() == NULL),
- "Space should be clear or mangled");
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::head_as_TreeChunk() {
- assert(head() == NULL || (TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head())->list() == this),
- "Wrong type of chunk?");
- return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head());
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::first_available() {
- assert(head() != NULL, "The head of the list cannot be NULL");
- Chunk_t* fc = head()->next();
- TreeChunk<Chunk_t, FreeList_t>* retTC;
- if (fc == NULL) {
- retTC = head_as_TreeChunk();
- } else {
- retTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(fc);
- }
- assert(retTC->list() == this, "Wrong type of chunk.");
- return retTC;
-}
-
-// Returns the block with the largest heap address amongst
-// those in the list for this size; potentially slow and expensive,
-// use with caution!
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::largest_address() {
- assert(head() != NULL, "The head of the list cannot be NULL");
- Chunk_t* fc = head()->next();
- TreeChunk<Chunk_t, FreeList_t>* retTC;
- if (fc == NULL) {
- retTC = head_as_TreeChunk();
- } else {
- // walk down the list and return the one with the highest
- // heap address among chunks of this size.
- Chunk_t* last = fc;
- while (fc->next() != NULL) {
- if ((HeapWord*)last < (HeapWord*)fc) {
- last = fc;
- }
- fc = fc->next();
- }
- retTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(last);
- }
- assert(retTC->list() == this, "Wrong type of chunk.");
- return retTC;
-}
-
-template <class Chunk_t, class FreeList_t>
-BinaryTreeDictionary<Chunk_t, FreeList_t>::BinaryTreeDictionary(MemRegion mr) {
- assert((mr.byte_size() > min_size()), "minimum chunk size");
-
- reset(mr);
- assert(root()->left() == NULL, "reset check failed");
- assert(root()->right() == NULL, "reset check failed");
- assert(root()->head()->next() == NULL, "reset check failed");
- assert(root()->head()->prev() == NULL, "reset check failed");
- assert(total_size() == root()->size(), "reset check failed");
- assert(total_free_blocks() == 1, "reset check failed");
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::inc_total_size(size_t inc) {
- _total_size = _total_size + inc;
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::dec_total_size(size_t dec) {
- _total_size = _total_size - dec;
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(MemRegion mr) {
- assert((mr.byte_size() > min_size()), "minimum chunk size");
- set_root(TreeList<Chunk_t, FreeList_t>::as_TreeList(mr.start(), mr.word_size()));
- set_total_size(mr.word_size());
- set_total_free_blocks(1);
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(HeapWord* addr, size_t byte_size) {
- MemRegion mr(addr, heap_word_size(byte_size));
- reset(mr);
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset() {
- set_root(NULL);
- set_total_size(0);
- set_total_free_blocks(0);
-}
-
-// Get a free block of size at least size from tree, or NULL.
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>*
-BinaryTreeDictionary<Chunk_t, FreeList_t>::get_chunk_from_tree(size_t size)
-{
- TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
- TreeChunk<Chunk_t, FreeList_t>* retTC = NULL;
-
- assert((size >= min_size()), "minimum chunk size");
- if (FLSVerifyDictionary) {
- verify_tree();
- }
- // starting at the root, work downwards trying to find match.
- // Remember the last node of size too great or too small.
- for (prevTL = curTL = root(); curTL != NULL;) {
- if (curTL->size() == size) { // exact match
- break;
- }
- prevTL = curTL;
- if (curTL->size() < size) { // proceed to right sub-tree
- curTL = curTL->right();
- } else { // proceed to left sub-tree
- assert(curTL->size() > size, "size inconsistency");
- curTL = curTL->left();
- }
- }
- if (curTL == NULL) { // couldn't find exact match
-
- // try and find the next larger size by walking back up the search path
- for (curTL = prevTL; curTL != NULL;) {
- if (curTL->size() >= size) break;
- else curTL = curTL->parent();
- }
- assert(curTL == NULL || curTL->count() > 0,
- "An empty list should not be in the tree");
- }
- if (curTL != NULL) {
- assert(curTL->size() >= size, "size inconsistency");
-
- curTL = curTL->get_better_list(this);
-
- retTC = curTL->first_available();
- assert((retTC != NULL) && (curTL->count() > 0),
- "A list in the binary tree should not be NULL");
- assert(retTC->size() >= size,
- "A chunk of the wrong size was found");
- remove_chunk_from_tree(retTC);
- assert(retTC->is_free(), "Header is not marked correctly");
- }
-
- if (FLSVerifyDictionary) {
- verify();
- }
- return retTC;
-}
-
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_list(size_t size) const {
- TreeList<Chunk_t, FreeList_t>* curTL;
- for (curTL = root(); curTL != NULL;) {
- if (curTL->size() == size) { // exact match
- break;
- }
-
- if (curTL->size() < size) { // proceed to right sub-tree
- curTL = curTL->right();
- } else { // proceed to left sub-tree
- assert(curTL->size() > size, "size inconsistency");
- curTL = curTL->left();
- }
- }
- return curTL;
-}
-
-
-template <class Chunk_t, class FreeList_t>
-bool BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_chunk_in_free_list(Chunk_t* tc) const {
- size_t size = tc->size();
- TreeList<Chunk_t, FreeList_t>* tl = find_list(size);
- if (tl == NULL) {
- return false;
- } else {
- return tl->verify_chunk_in_free_list(tc);
- }
-}
-
-template <class Chunk_t, class FreeList_t>
-Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_largest_dict() const {
- TreeList<Chunk_t, FreeList_t> *curTL = root();
- if (curTL != NULL) {
- while(curTL->right() != NULL) curTL = curTL->right();
- return curTL->largest_address();
- } else {
- return NULL;
- }
-}
-
-// Remove the current chunk from the tree. If it is not the last
-// chunk in a list on a tree node, just unlink it.
-// If it is the last chunk in the list (the next link is NULL),
-// remove the node and repair the tree.
-template <class Chunk_t, class FreeList_t>
-TreeChunk<Chunk_t, FreeList_t>*
-BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_chunk_from_tree(TreeChunk<Chunk_t, FreeList_t>* tc) {
- assert(tc != NULL, "Should not call with a NULL chunk");
- assert(tc->is_free(), "Header is not marked correctly");
-
- TreeList<Chunk_t, FreeList_t> *newTL, *parentTL;
- TreeChunk<Chunk_t, FreeList_t>* retTC;
- TreeList<Chunk_t, FreeList_t>* tl = tc->list();
- debug_only(
- bool removing_only_chunk = false;
- if (tl == _root) {
- if ((_root->left() == NULL) && (_root->right() == NULL)) {
- if (_root->count() == 1) {
- assert(_root->head() == tc, "Should only be this one chunk");
- removing_only_chunk = true;
- }
- }
- }
- )
- assert(tl != NULL, "List should be set");
- assert(tl->parent() == NULL || tl == tl->parent()->left() ||
- tl == tl->parent()->right(), "list is inconsistent");
-
- bool complicated_splice = false;
-
- retTC = tc;
- // Removing this chunk can have the side effect of changing the node
- // (TreeList<Chunk_t, FreeList_t>*) in the tree. If the node is the root, update it.
- TreeList<Chunk_t, FreeList_t>* replacementTL = tl->remove_chunk_replace_if_needed(tc);
- assert(tc->is_free(), "Chunk should still be free");
- assert(replacementTL->parent() == NULL ||
- replacementTL == replacementTL->parent()->left() ||
- replacementTL == replacementTL->parent()->right(),
- "list is inconsistent");
- if (tl == root()) {
- assert(replacementTL->parent() == NULL, "Incorrectly replacing root");
- set_root(replacementTL);
- }
-#ifdef ASSERT
- if (tl != replacementTL) {
- assert(replacementTL->head() != NULL,
- "If the tree list was replaced, it should not be a NULL list");
- TreeList<Chunk_t, FreeList_t>* rhl = replacementTL->head_as_TreeChunk()->list();
- TreeList<Chunk_t, FreeList_t>* rtl =
- TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(replacementTL->tail())->list();
- assert(rhl == replacementTL, "Broken head");
- assert(rtl == replacementTL, "Broken tail");
- assert(replacementTL->size() == tc->size(), "Broken size");
- }
-#endif
-
- // Does the tree need to be repaired?
- if (replacementTL->count() == 0) {
- assert(replacementTL->head() == NULL &&
- replacementTL->tail() == NULL, "list count is incorrect");
- // Find the replacement node for the (soon to be empty) node being removed.
- // if we have a single (or no) child, splice child in our stead
- if (replacementTL->left() == NULL) {
- // left is NULL so pick right. right may also be NULL.
- newTL = replacementTL->right();
- debug_only(replacementTL->clear_right();)
- } else if (replacementTL->right() == NULL) {
- // right is NULL
- newTL = replacementTL->left();
- debug_only(replacementTL->clear_left();)
- } else { // we have both children, so, by patriarchal convention,
- // my replacement is least node in right sub-tree
- complicated_splice = true;
- newTL = remove_tree_minimum(replacementTL->right());
- assert(newTL != NULL && newTL->left() == NULL &&
- newTL->right() == NULL, "sub-tree minimum exists");
- }
- // newTL is the replacement for the (soon to be empty) node.
- // newTL may be NULL.
- // should verify; we just cleanly excised our replacement
- if (FLSVerifyDictionary) {
- verify_tree();
- }
- // first make newTL my parent's child
- if ((parentTL = replacementTL->parent()) == NULL) {
- // newTL should be root
- assert(tl == root(), "Incorrectly replacing root");
- set_root(newTL);
- if (newTL != NULL) {
- newTL->clear_parent();
- }
- } else if (parentTL->right() == replacementTL) {
- // replacementTL is a right child
- parentTL->set_right(newTL);
- } else { // replacementTL is a left child
- assert(parentTL->left() == replacementTL, "should be left child");
- parentTL->set_left(newTL);
- }
- debug_only(replacementTL->clear_parent();)
- if (complicated_splice) { // we need newTL to get replacementTL's
- // two children
- assert(newTL != NULL &&
- newTL->left() == NULL && newTL->right() == NULL,
- "newTL should not have encumbrances from the past");
- // we'd like to assert as below:
- // assert(replacementTL->left() != NULL && replacementTL->right() != NULL,
- // "else !complicated_splice");
- // ... however, the above assertion is too strong because we aren't
- // guaranteed that replacementTL->right() is still NULL.
- // Recall that we removed
- // the right sub-tree minimum from replacementTL.
- // That may well have been its right
- // child! So we'll just assert half of the above:
- assert(replacementTL->left() != NULL, "else !complicated_splice");
- newTL->set_left(replacementTL->left());
- newTL->set_right(replacementTL->right());
- debug_only(
- replacementTL->clear_right();
- replacementTL->clear_left();
- )
- }
- assert(replacementTL->right() == NULL &&
- replacementTL->left() == NULL &&
- replacementTL->parent() == NULL,
- "delete without encumbrances");
- }
-
- assert(total_size() >= retTC->size(), "Incorrect total size");
- dec_total_size(retTC->size()); // size book-keeping
- assert(total_free_blocks() > 0, "Incorrect total count");
- set_total_free_blocks(total_free_blocks() - 1);
-
- assert(retTC != NULL, "null chunk?");
- assert(retTC->prev() == NULL && retTC->next() == NULL,
- "should return without encumbrances");
- if (FLSVerifyDictionary) {
- verify_tree();
- }
- assert(!removing_only_chunk || _root == NULL, "root should be NULL");
- return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(retTC);
-}
-
-// Remove the leftmost node (lm) in the tree and return it.
-// If lm has a right child, link it to the left node of
-// the parent of lm.
-template <class Chunk_t, class FreeList_t>
-TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_tree_minimum(TreeList<Chunk_t, FreeList_t>* tl) {
- assert(tl != NULL && tl->parent() != NULL, "really need a proper sub-tree");
- // locate the subtree minimum by walking down left branches
- TreeList<Chunk_t, FreeList_t>* curTL = tl;
- for (; curTL->left() != NULL; curTL = curTL->left());
- // obviously curTL now has at most one child, a right child
- if (curTL != root()) { // Should this test just be removed?
- TreeList<Chunk_t, FreeList_t>* parentTL = curTL->parent();
- if (parentTL->left() == curTL) { // curTL is a left child
- parentTL->set_left(curTL->right());
- } else {
- // If the list tl has no left child, then curTL may be
- // the right child of parentTL.
- assert(parentTL->right() == curTL, "should be a right child");
- parentTL->set_right(curTL->right());
- }
- } else {
- // The only use of this method would not pass the root of the
- // tree (as indicated by the assertion above that the tree list
- // has a parent) but the specification does not explicitly exclude the
- // passing of the root so accommodate it.
- set_root(NULL);
- }
- debug_only(
- curTL->clear_parent(); // Test if this needs to be cleared
- curTL->clear_right(); // recall, above, left child is already null
- )
- // we just excised a (non-root) node, we should still verify all tree invariants
- if (FLSVerifyDictionary) {
- verify_tree();
- }
- return curTL;
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::insert_chunk_in_tree(Chunk_t* fc) {
- TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
- size_t size = fc->size();
-
- assert((size >= min_size()),
- SIZE_FORMAT " is too small to be a TreeChunk<Chunk_t, FreeList_t> " SIZE_FORMAT,
- size, min_size());
- if (FLSVerifyDictionary) {
- verify_tree();
- }
-
- fc->clear_next();
- fc->link_prev(NULL);
-
- // work down from the _root, looking for insertion point
- for (prevTL = curTL = root(); curTL != NULL;) {
- if (curTL->size() == size) // exact match
- break;
- prevTL = curTL;
- if (curTL->size() > size) { // follow left branch
- curTL = curTL->left();
- } else { // follow right branch
- assert(curTL->size() < size, "size inconsistency");
- curTL = curTL->right();
- }
- }
- TreeChunk<Chunk_t, FreeList_t>* tc = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(fc);
- // This chunk is being returned to the binary tree. Its embedded
- // TreeList<Chunk_t, FreeList_t> should be unused at this point.
- tc->initialize();
- if (curTL != NULL) { // exact match
- tc->set_list(curTL);
- curTL->return_chunk_at_tail(tc);
- } else { // need a new node in tree
- tc->clear_next();
- tc->link_prev(NULL);
- TreeList<Chunk_t, FreeList_t>* newTL = TreeList<Chunk_t, FreeList_t>::as_TreeList(tc);
- assert(((TreeChunk<Chunk_t, FreeList_t>*)tc)->list() == newTL,
- "List was not initialized correctly");
- if (prevTL == NULL) { // we are the only tree node
- assert(root() == NULL, "control point invariant");
- set_root(newTL);
- } else { // insert under prevTL ...
- if (prevTL->size() < size) { // am right child
- assert(prevTL->right() == NULL, "control point invariant");
- prevTL->set_right(newTL);
- } else { // am left child
- assert(prevTL->size() > size && prevTL->left() == NULL, "cpt pt inv");
- prevTL->set_left(newTL);
- }
- }
- }
- assert(tc->list() != NULL, "Tree list should be set");
-
- inc_total_size(size);
- // Method 'total_size_in_tree' walks through the every block in the
- // tree, so it can cause significant performance loss if there are
- // many blocks in the tree
- assert(!FLSVerifyDictionary || total_size_in_tree(root()) == total_size(), "_total_size inconsistency");
- set_total_free_blocks(total_free_blocks() + 1);
- if (FLSVerifyDictionary) {
- verify_tree();
- }
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::max_chunk_size() const {
- verify_par_locked();
- TreeList<Chunk_t, FreeList_t>* tc = root();
- if (tc == NULL) return 0;
- for (; tc->right() != NULL; tc = tc->right());
- return tc->size();
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_list_length(TreeList<Chunk_t, FreeList_t>* tl) const {
- size_t res;
- res = tl->count();
-#ifdef ASSERT
- size_t cnt;
- Chunk_t* tc = tl->head();
- for (cnt = 0; tc != NULL; tc = tc->next(), cnt++);
- assert(res == cnt, "The count is not being maintained correctly");
-#endif
- return res;
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_size_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
- if (tl == NULL)
- return 0;
- return (tl->size() * total_list_length(tl)) +
- total_size_in_tree(tl->left()) +
- total_size_in_tree(tl->right());
-}
-
-template <class Chunk_t, class FreeList_t>
-double BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_of_squared_block_sizes(TreeList<Chunk_t, FreeList_t>* const tl) const {
- if (tl == NULL) {
- return 0.0;
- }
- double size = (double)(tl->size());
- double curr = size * size * total_list_length(tl);
- curr += sum_of_squared_block_sizes(tl->left());
- curr += sum_of_squared_block_sizes(tl->right());
- return curr;
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_free_blocks_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
- if (tl == NULL)
- return 0;
- return total_list_length(tl) +
- total_free_blocks_in_tree(tl->left()) +
- total_free_blocks_in_tree(tl->right());
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::num_free_blocks() const {
- assert(total_free_blocks_in_tree(root()) == total_free_blocks(),
- "_total_free_blocks inconsistency");
- return total_free_blocks();
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
- if (tl == NULL)
- return 0;
- return 1 + MAX2(tree_height_helper(tl->left()),
- tree_height_helper(tl->right()));
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height() const {
- return tree_height_helper(root());
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
- if (tl == NULL) {
- return 0;
- }
- return 1 + total_nodes_helper(tl->left()) +
- total_nodes_helper(tl->right());
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
- return total_nodes_helper(root());
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::dict_census_update(size_t size, bool split, bool birth){}
-
-#if INCLUDE_ALL_GCS
-template <>
-void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth) {
- TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* nd = find_list(size);
- if (nd) {
- if (split) {
- if (birth) {
- nd->increment_split_births();
- nd->increment_surplus();
- } else {
- nd->increment_split_deaths();
- nd->decrement_surplus();
- }
- } else {
- if (birth) {
- nd->increment_coal_births();
- nd->increment_surplus();
- } else {
- nd->increment_coal_deaths();
- nd->decrement_surplus();
- }
- }
- }
- // A list for this size may not be found (nd == 0) if
- // This is a death where the appropriate list is now
- // empty and has been removed from the list.
- // This is a birth associated with a LinAB. The chunk
- // for the LinAB is not in the dictionary.
-}
-#endif // INCLUDE_ALL_GCS
-
-template <class Chunk_t, class FreeList_t>
-bool BinaryTreeDictionary<Chunk_t, FreeList_t>::coal_dict_over_populated(size_t size) {
- // For the general type of freelists, encourage coalescing by
- // returning true.
- return true;
-}
-
-#if INCLUDE_ALL_GCS
-template <>
-bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) {
- if (FLSAlwaysCoalesceLarge) return true;
-
- TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* list_of_size = find_list(size);
- // None of requested size implies overpopulated.
- return list_of_size == NULL || list_of_size->coal_desired() <= 0 ||
- list_of_size->count() > list_of_size->coal_desired();
-}
-#endif // INCLUDE_ALL_GCS
-
-// Closures for walking the binary tree.
-// do_list() walks the free list in a node applying the closure
-// to each free chunk in the list
-// do_tree() walks the nodes in the binary tree applying do_list()
-// to each list at each node.
-
-template <class Chunk_t, class FreeList_t>
-class TreeCensusClosure : public StackObj {
- protected:
- virtual void do_list(FreeList_t* fl) = 0;
- public:
- virtual void do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
-};
-
-template <class Chunk_t, class FreeList_t>
-class AscendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
- public:
- void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
- if (tl != NULL) {
- do_tree(tl->left());
- this->do_list(tl);
- do_tree(tl->right());
- }
- }
-};
-
-template <class Chunk_t, class FreeList_t>
-class DescendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
- public:
- void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
- if (tl != NULL) {
- do_tree(tl->right());
- this->do_list(tl);
- do_tree(tl->left());
- }
- }
-};
-
-// For each list in the tree, calculate the desired, desired
-// coalesce, count before sweep, and surplus before sweep.
-template <class Chunk_t, class FreeList_t>
-class BeginSweepClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- double _percentage;
- float _inter_sweep_current;
- float _inter_sweep_estimate;
- float _intra_sweep_estimate;
-
- public:
- BeginSweepClosure(double p, float inter_sweep_current,
- float inter_sweep_estimate,
- float intra_sweep_estimate) :
- _percentage(p),
- _inter_sweep_current(inter_sweep_current),
- _inter_sweep_estimate(inter_sweep_estimate),
- _intra_sweep_estimate(intra_sweep_estimate) { }
-
- void do_list(FreeList<Chunk_t>* fl) {}
-
-#if INCLUDE_ALL_GCS
- void do_list(AdaptiveFreeList<Chunk_t>* fl) {
- double coalSurplusPercent = _percentage;
- fl->compute_desired(_inter_sweep_current, _inter_sweep_estimate, _intra_sweep_estimate);
- fl->set_coal_desired((ssize_t)((double)fl->desired() * coalSurplusPercent));
- fl->set_before_sweep(fl->count());
- fl->set_bfr_surp(fl->surplus());
- }
-#endif // INCLUDE_ALL_GCS
-};
-
-// Used to search the tree until a condition is met.
-// Similar to TreeCensusClosure but searches the
-// tree and returns promptly when found.
-
-template <class Chunk_t, class FreeList_t>
-class TreeSearchClosure : public StackObj {
- protected:
- virtual bool do_list(FreeList_t* fl) = 0;
- public:
- virtual bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
-};
-
-#if 0 // Don't need this yet but here for symmetry.
-template <class Chunk_t, class FreeList_t>
-class AscendTreeSearchClosure : public TreeSearchClosure<Chunk_t> {
- public:
- bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
- if (tl != NULL) {
- if (do_tree(tl->left())) return true;
- if (do_list(tl)) return true;
- if (do_tree(tl->right())) return true;
- }
- return false;
- }
-};
-#endif
-
-template <class Chunk_t, class FreeList_t>
-class DescendTreeSearchClosure : public TreeSearchClosure<Chunk_t, FreeList_t> {
- public:
- bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
- if (tl != NULL) {
- if (do_tree(tl->right())) return true;
- if (this->do_list(tl)) return true;
- if (do_tree(tl->left())) return true;
- }
- return false;
- }
-};
-
-// Searches the tree for a chunk that ends at the
-// specified address.
-template <class Chunk_t, class FreeList_t>
-class EndTreeSearchClosure : public DescendTreeSearchClosure<Chunk_t, FreeList_t> {
- HeapWord* _target;
- Chunk_t* _found;
-
- public:
- EndTreeSearchClosure(HeapWord* target) : _target(target), _found(NULL) {}
- bool do_list(FreeList_t* fl) {
- Chunk_t* item = fl->head();
- while (item != NULL) {
- if (item->end() == (uintptr_t*) _target) {
- _found = item;
- return true;
- }
- item = item->next();
- }
- return false;
- }
- Chunk_t* found() { return _found; }
-};
-
-template <class Chunk_t, class FreeList_t>
-Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_chunk_ends_at(HeapWord* target) const {
- EndTreeSearchClosure<Chunk_t, FreeList_t> etsc(target);
- bool found_target = etsc.do_tree(root());
- assert(found_target || etsc.found() == NULL, "Consistency check");
- assert(!found_target || etsc.found() != NULL, "Consistency check");
- return etsc.found();
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::begin_sweep_dict_census(double coalSurplusPercent,
- float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
- BeginSweepClosure<Chunk_t, FreeList_t> bsc(coalSurplusPercent, inter_sweep_current,
- inter_sweep_estimate,
- intra_sweep_estimate);
- bsc.do_tree(root());
-}
-
-// Closures and methods for calculating total bytes returned to the
-// free lists in the tree.
-#ifndef PRODUCT
-template <class Chunk_t, class FreeList_t>
-class InitializeDictReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- public:
- void do_list(FreeList_t* fl) {
- fl->set_returned_bytes(0);
- }
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::initialize_dict_returned_bytes() {
- InitializeDictReturnedBytesClosure<Chunk_t, FreeList_t> idrb;
- idrb.do_tree(root());
-}
-
-template <class Chunk_t, class FreeList_t>
-class ReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- size_t _dict_returned_bytes;
- public:
- ReturnedBytesClosure() { _dict_returned_bytes = 0; }
- void do_list(FreeList_t* fl) {
- _dict_returned_bytes += fl->returned_bytes();
- }
- size_t dict_returned_bytes() { return _dict_returned_bytes; }
-};
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_dict_returned_bytes() {
- ReturnedBytesClosure<Chunk_t, FreeList_t> rbc;
- rbc.do_tree(root());
-
- return rbc.dict_returned_bytes();
-}
-
-// Count the number of entries in the tree.
-template <class Chunk_t, class FreeList_t>
-class treeCountClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
- public:
- uint count;
- treeCountClosure(uint c) { count = c; }
- void do_list(FreeList_t* fl) {
- count++;
- }
-};
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_count() {
- treeCountClosure<Chunk_t, FreeList_t> ctc(0);
- ctc.do_tree(root());
- return ctc.count;
-}
-
-template <class Chunk_t, class FreeList_t>
-Mutex* BinaryTreeDictionary<Chunk_t, FreeList_t>::par_lock() const {
- return _lock;
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_par_lock(Mutex* lock) {
- _lock = lock;
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_par_locked() const {
-#ifdef ASSERT
- Thread* my_thread = Thread::current();
- if (my_thread->is_GC_task_thread()) {
- assert(par_lock() != NULL, "Should be using locking?");
- assert_lock_strong(par_lock());
- }
-#endif // ASSERT
-}
-#endif // PRODUCT
-
-// Calculate surpluses for the lists in the tree.
-template <class Chunk_t, class FreeList_t>
-class setTreeSurplusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- double percentage;
- public:
- setTreeSurplusClosure(double v) { percentage = v; }
- void do_list(FreeList<Chunk_t>* fl) {}
-
-#if INCLUDE_ALL_GCS
- void do_list(AdaptiveFreeList<Chunk_t>* fl) {
- double splitSurplusPercent = percentage;
- fl->set_surplus(fl->count() -
- (ssize_t)((double)fl->desired() * splitSurplusPercent));
- }
-#endif // INCLUDE_ALL_GCS
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_tree_surplus(double splitSurplusPercent) {
- setTreeSurplusClosure<Chunk_t, FreeList_t> sts(splitSurplusPercent);
- sts.do_tree(root());
-}
-
-// Set hints for the lists in the tree.
-template <class Chunk_t, class FreeList_t>
-class setTreeHintsClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
- size_t hint;
- public:
- setTreeHintsClosure(size_t v) { hint = v; }
- void do_list(FreeList<Chunk_t>* fl) {}
-
-#if INCLUDE_ALL_GCS
- void do_list(AdaptiveFreeList<Chunk_t>* fl) {
- fl->set_hint(hint);
- assert(fl->hint() == 0 || fl->hint() > fl->size(),
- "Current hint is inconsistent");
- if (fl->surplus() > 0) {
- hint = fl->size();
- }
- }
-#endif // INCLUDE_ALL_GCS
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_tree_hints(void) {
- setTreeHintsClosure<Chunk_t, FreeList_t> sth(0);
- sth.do_tree(root());
-}
-
-// Save count before previous sweep and splits and coalesces.
-template <class Chunk_t, class FreeList_t>
-class clearTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- void do_list(FreeList<Chunk_t>* fl) {}
-
-#if INCLUDE_ALL_GCS
- void do_list(AdaptiveFreeList<Chunk_t>* fl) {
- fl->set_prev_sweep(fl->count());
- fl->set_coal_births(0);
- fl->set_coal_deaths(0);
- fl->set_split_births(0);
- fl->set_split_deaths(0);
- }
-#endif // INCLUDE_ALL_GCS
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::clear_tree_census(void) {
- clearTreeCensusClosure<Chunk_t, FreeList_t> ctc;
- ctc.do_tree(root());
-}
-
-// Do reporting and post sweep clean up.
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::end_sweep_dict_census(double splitSurplusPercent) {
- // Does walking the tree 3 times hurt?
- set_tree_surplus(splitSurplusPercent);
- set_tree_hints();
- LogTarget(Trace, gc, freelist, stats) log;
- if (log.is_enabled()) {
- LogStream out(log);
- report_statistics(&out);
- }
- clear_tree_census();
-}
-
-// Print summary statistics
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::report_statistics(outputStream* st) const {
- verify_par_locked();
- st->print_cr("Statistics for BinaryTreeDictionary:");
- st->print_cr("------------------------------------");
- size_t total_size = total_chunk_size(debug_only(NULL));
- size_t free_blocks = num_free_blocks();
- st->print_cr("Total Free Space: " SIZE_FORMAT, total_size);
- st->print_cr("Max Chunk Size: " SIZE_FORMAT, max_chunk_size());
- st->print_cr("Number of Blocks: " SIZE_FORMAT, free_blocks);
- if (free_blocks > 0) {
- st->print_cr("Av. Block Size: " SIZE_FORMAT, total_size/free_blocks);
- }
- st->print_cr("Tree Height: " SIZE_FORMAT, tree_height());
-}
-
-// Print census information - counts, births, deaths, etc.
-// for each list in the tree. Also print some summary
-// information.
-template <class Chunk_t, class FreeList_t>
-class PrintTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- int _print_line;
- size_t _total_free;
- FreeList_t _total;
-
- public:
- PrintTreeCensusClosure() {
- _print_line = 0;
- _total_free = 0;
- }
- FreeList_t* total() { return &_total; }
- size_t total_free() { return _total_free; }
- void do_list(FreeList<Chunk_t>* fl) {
- LogStreamHandle(Debug, gc, freelist, census) out;
-
- if (++_print_line >= 40) {
- FreeList_t::print_labels_on(&out, "size");
- _print_line = 0;
- }
- fl->print_on(&out);
- _total_free += fl->count() * fl->size();
- total()->set_count(total()->count() + fl->count());
- }
-
-#if INCLUDE_ALL_GCS
- void do_list(AdaptiveFreeList<Chunk_t>* fl) {
- LogStreamHandle(Debug, gc, freelist, census) out;
-
- if (++_print_line >= 40) {
- FreeList_t::print_labels_on(&out, "size");
- _print_line = 0;
- }
- fl->print_on(&out);
- _total_free += fl->count() * fl->size() ;
- total()->set_count( total()->count() + fl->count() );
- total()->set_bfr_surp( total()->bfr_surp() + fl->bfr_surp() );
- total()->set_surplus( total()->split_deaths() + fl->surplus() );
- total()->set_desired( total()->desired() + fl->desired() );
- total()->set_prev_sweep( total()->prev_sweep() + fl->prev_sweep() );
- total()->set_before_sweep(total()->before_sweep() + fl->before_sweep());
- total()->set_coal_births( total()->coal_births() + fl->coal_births() );
- total()->set_coal_deaths( total()->coal_deaths() + fl->coal_deaths() );
- total()->set_split_births(total()->split_births() + fl->split_births());
- total()->set_split_deaths(total()->split_deaths() + fl->split_deaths());
- }
-#endif // INCLUDE_ALL_GCS
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_dict_census(outputStream* st) const {
-
- st->print("BinaryTree");
- FreeList_t::print_labels_on(st, "size");
- PrintTreeCensusClosure<Chunk_t, FreeList_t> ptc;
- ptc.do_tree(root());
-
- FreeList_t* total = ptc.total();
- FreeList_t::print_labels_on(st, " ");
-}
-
-#if INCLUDE_ALL_GCS
-template <>
-void AFLBinaryTreeDictionary::print_dict_census(outputStream* st) const {
-
- st->print_cr("BinaryTree");
- AdaptiveFreeList<FreeChunk>::print_labels_on(st, "size");
- PrintTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > ptc;
- ptc.do_tree(root());
-
- AdaptiveFreeList<FreeChunk>* total = ptc.total();
- AdaptiveFreeList<FreeChunk>::print_labels_on(st, " ");
- total->print_on(st, "TOTAL\t");
- st->print_cr("total_free(words): " SIZE_FORMAT_W(16) " growth: %8.5f deficit: %8.5f",
- ptc.total_free(),
- (double)(total->split_births() + total->coal_births()
- - total->split_deaths() - total->coal_deaths())
- /(total->prev_sweep() != 0 ? (double)total->prev_sweep() : 1.0),
- (double)(total->desired() - total->count())
- /(total->desired() != 0 ? (double)total->desired() : 1.0));
-}
-#endif // INCLUDE_ALL_GCS
-
-template <class Chunk_t, class FreeList_t>
-class PrintFreeListsClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
- outputStream* _st;
- int _print_line;
-
- public:
- PrintFreeListsClosure(outputStream* st) {
- _st = st;
- _print_line = 0;
- }
- void do_list(FreeList_t* fl) {
- if (++_print_line >= 40) {
- FreeList_t::print_labels_on(_st, "size");
- _print_line = 0;
- }
- fl->print_on(_st);
- size_t sz = fl->size();
- for (Chunk_t* fc = fl->head(); fc != NULL;
- fc = fc->next()) {
- _st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s",
- p2i(fc), p2i((HeapWord*)fc + sz),
- fc->cantCoalesce() ? "\t CC" : "");
- }
- }
-};
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_free_lists(outputStream* st) const {
-
- FreeList_t::print_labels_on(st, "size");
- PrintFreeListsClosure<Chunk_t, FreeList_t> pflc(st);
- pflc.do_tree(root());
-}
-
-// Verify the following tree invariants:
-// . _root has no parent
-// . parent and child point to each other
-// . each node's key correctly related to that of its child(ren)
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree() const {
- guarantee(root() == NULL || total_free_blocks() == 0 ||
- total_size() != 0, "_total_size shouldn't be 0?");
- guarantee(root() == NULL || root()->parent() == NULL, "_root shouldn't have parent");
- verify_tree_helper(root());
-}
-
-template <class Chunk_t, class FreeList_t>
-size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_prev_free_ptrs(TreeList<Chunk_t, FreeList_t>* tl) {
- size_t ct = 0;
- for (Chunk_t* curFC = tl->head(); curFC != NULL; curFC = curFC->next()) {
- ct++;
- assert(curFC->prev() == NULL || curFC->prev()->is_free(),
- "Chunk should be free");
- }
- return ct;
-}
-
-// Note: this helper is recursive rather than iterative, so use with
-// caution on very deep trees; and watch out for stack overflow errors;
-// In general, to be used only for debugging.
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
- if (tl == NULL)
- return;
- guarantee(tl->size() != 0, "A list must has a size");
- guarantee(tl->left() == NULL || tl->left()->parent() == tl,
- "parent<-/->left");
- guarantee(tl->right() == NULL || tl->right()->parent() == tl,
- "parent<-/->right");;
- guarantee(tl->left() == NULL || tl->left()->size() < tl->size(),
- "parent !> left");
- guarantee(tl->right() == NULL || tl->right()->size() > tl->size(),
- "parent !< left");
- guarantee(tl->head() == NULL || tl->head()->is_free(), "!Free");
- guarantee(tl->head() == NULL || tl->head_as_TreeChunk()->list() == tl,
- "list inconsistency");
- guarantee(tl->count() > 0 || (tl->head() == NULL && tl->tail() == NULL),
- "list count is inconsistent");
- guarantee(tl->count() > 1 || tl->head() == tl->tail(),
- "list is incorrectly constructed");
- size_t count = verify_prev_free_ptrs(tl);
- guarantee(count == (size_t)tl->count(), "Node count is incorrect");
- if (tl->head() != NULL) {
- tl->head_as_TreeChunk()->verify_tree_chunk_list();
- }
- verify_tree_helper(tl->left());
- verify_tree_helper(tl->right());
-}
-
-template <class Chunk_t, class FreeList_t>
-void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify() const {
- verify_tree();
- guarantee(total_size() == total_size_in_tree(root()), "Total Size inconsistency");
-}
-
-template class TreeList<Metablock, FreeList<Metablock> >;
-template class BinaryTreeDictionary<Metablock, FreeList<Metablock> >;
-template class TreeChunk<Metablock, FreeList<Metablock> >;
-
-template class TreeList<Metachunk, FreeList<Metachunk> >;
-template class BinaryTreeDictionary<Metachunk, FreeList<Metachunk> >;
-template class TreeChunk<Metachunk, FreeList<Metachunk> >;
-
-
-#if INCLUDE_ALL_GCS
-// Explicitly instantiate these types for FreeChunk.
-template class TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >;
-template class BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> >;
-template class TreeChunk<FreeChunk, AdaptiveFreeList<FreeChunk> >;
-
-#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/share/memory/binaryTreeDictionary.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/memory/binaryTreeDictionary.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -42,10 +42,6 @@
template <class Chunk_t, class FreeList_t> class DescendTreeCensusClosure;
template <class Chunk_t, class FreeList_t> class DescendTreeSearchClosure;
-class FreeChunk;
-template <class> class AdaptiveFreeList;
-typedef BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> > AFLBinaryTreeDictionary;
-
template <class Chunk_t, class FreeList_t>
class TreeList : public FreeList_t {
friend class TreeChunk<Chunk_t, FreeList_t>;
@@ -177,6 +173,8 @@
template <class Chunk_t, class FreeList_t>
class BinaryTreeDictionary: public CHeapObj<mtGC> {
friend class VMStructs;
+
+ protected:
size_t _total_size;
size_t _total_free_blocks;
TreeList<Chunk_t, FreeList_t>* _root;
@@ -298,32 +296,9 @@
Chunk_t* find_chunk_ends_at(HeapWord* target) const;
- // Find the list with size "size" in the binary tree and update
- // the statistics in the list according to "split" (chunk was
- // split or coalesce) and "birth" (chunk was added or removed).
- void dict_census_update(size_t size, bool split, bool birth);
- // Return true if the dictionary is overpopulated (more chunks of
- // this size than desired) for size "size".
- bool coal_dict_over_populated(size_t size);
- // Methods called at the beginning of a sweep to prepare the
- // statistics for the sweep.
- void begin_sweep_dict_census(double coalSurplusPercent,
- float inter_sweep_current,
- float inter_sweep_estimate,
- float intra_sweep_estimate);
- // Methods called after the end of a sweep to modify the
- // statistics for the sweep.
- void end_sweep_dict_census(double splitSurplusPercent);
// Return the largest free chunk in the tree.
Chunk_t* find_largest_dict() const;
- // Accessors for statistics
- void set_tree_surplus(double splitSurplusPercent);
- void set_tree_hints(void);
- // Reset statistics for all the lists in the tree.
- void clear_tree_census(void);
- // Print the statistics for all the lists in the tree. Also may
- // print out summaries.
- void print_dict_census(outputStream* st) const;
+
void print_free_lists(outputStream* st) const;
// For debugging. Returns the sum of the _returned_bytes for
@@ -343,4 +318,83 @@
void verify_par_locked() const PRODUCT_RETURN;
};
+
+// Closures for walking the binary tree.
+// do_list() walks the free list in a node applying the closure
+// to each free chunk in the list
+// do_tree() walks the nodes in the binary tree applying do_list()
+// to each list at each node.
+
+template <class Chunk_t, class FreeList_t>
+class TreeCensusClosure : public StackObj {
+ protected:
+ virtual void do_list(FreeList_t* fl) = 0;
+ public:
+ virtual void do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
+};
+
+template <class Chunk_t, class FreeList_t>
+class AscendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
+ public:
+ void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
+ if (tl != NULL) {
+ do_tree(tl->left());
+ this->do_list(tl);
+ do_tree(tl->right());
+ }
+ }
+};
+
+template <class Chunk_t, class FreeList_t>
+class DescendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
+ public:
+ void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
+ if (tl != NULL) {
+ do_tree(tl->right());
+ this->do_list(tl);
+ do_tree(tl->left());
+ }
+ }
+};
+
+// Used to search the tree until a condition is met.
+// Similar to TreeCensusClosure but searches the
+// tree and returns promptly when found.
+
+template <class Chunk_t, class FreeList_t>
+class TreeSearchClosure : public StackObj {
+ protected:
+ virtual bool do_list(FreeList_t* fl) = 0;
+ public:
+ virtual bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
+};
+
+#if 0 // Don't need this yet but here for symmetry.
+template <class Chunk_t, class FreeList_t>
+class AscendTreeSearchClosure : public TreeSearchClosure<Chunk_t> {
+ public:
+ bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
+ if (tl != NULL) {
+ if (do_tree(tl->left())) return true;
+ if (do_list(tl)) return true;
+ if (do_tree(tl->right())) return true;
+ }
+ return false;
+ }
+};
+#endif
+
+template <class Chunk_t, class FreeList_t>
+class DescendTreeSearchClosure : public TreeSearchClosure<Chunk_t, FreeList_t> {
+ public:
+ bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
+ if (tl != NULL) {
+ if (do_tree(tl->right())) return true;
+ if (this->do_list(tl)) return true;
+ if (do_tree(tl->left())) return true;
+ }
+ return false;
+ }
+};
+
#endif // SHARE_VM_MEMORY_BINARYTREEDICTIONARY_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/binaryTreeDictionary.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,1025 @@
+/*
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * 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_MEMORY_BINARYTREEDICTIONARY_INLINE_HPP
+#define SHARE_VM_MEMORY_BINARYTREEDICTIONARY_INLINE_HPP
+
+#include "gc/shared/spaceDecorator.hpp"
+#include "logging/log.hpp"
+#include "logging/logStream.hpp"
+#include "memory/binaryTreeDictionary.hpp"
+#include "memory/freeList.inline.hpp"
+#include "memory/metachunk.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/globals.hpp"
+#include "utilities/macros.hpp"
+#include "utilities/ostream.hpp"
+
+////////////////////////////////////////////////////////////////////////////////
+// A binary tree based search structure for free blocks.
+// This is currently used in the Concurrent Mark&Sweep implementation.
+////////////////////////////////////////////////////////////////////////////////
+
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>* TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(Chunk_t* fc) {
+ // Do some assertion checking here.
+ return (TreeChunk<Chunk_t, FreeList_t>*) fc;
+}
+
+template <class Chunk_t, class FreeList_t>
+void TreeChunk<Chunk_t, FreeList_t>::verify_tree_chunk_list() const {
+ TreeChunk<Chunk_t, FreeList_t>* nextTC = (TreeChunk<Chunk_t, FreeList_t>*)next();
+ if (prev() != NULL) { // interior list node shouldn't have tree fields
+ guarantee(embedded_list()->parent() == NULL && embedded_list()->left() == NULL &&
+ embedded_list()->right() == NULL, "should be clear");
+ }
+ if (nextTC != NULL) {
+ guarantee(as_TreeChunk(nextTC->prev()) == this, "broken chain");
+ guarantee(nextTC->size() == size(), "wrong size");
+ nextTC->verify_tree_chunk_list();
+ }
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>::TreeList() : _parent(NULL),
+ _left(NULL), _right(NULL) {}
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>*
+TreeList<Chunk_t, FreeList_t>::as_TreeList(TreeChunk<Chunk_t,FreeList_t>* tc) {
+ // This first free chunk in the list will be the tree list.
+ assert((tc->size() >= (TreeChunk<Chunk_t, FreeList_t>::min_size())),
+ "Chunk is too small for a TreeChunk");
+ TreeList<Chunk_t, FreeList_t>* tl = tc->embedded_list();
+ tl->initialize();
+ tc->set_list(tl);
+ tl->set_size(tc->size());
+ tl->link_head(tc);
+ tl->link_tail(tc);
+ tl->set_count(1);
+ assert(tl->parent() == NULL, "Should be clear");
+ return tl;
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>*
+TreeList<Chunk_t, FreeList_t>::as_TreeList(HeapWord* addr, size_t size) {
+ TreeChunk<Chunk_t, FreeList_t>* tc = (TreeChunk<Chunk_t, FreeList_t>*) addr;
+ assert((size >= TreeChunk<Chunk_t, FreeList_t>::min_size()),
+ "Chunk is too small for a TreeChunk");
+ // The space will have been mangled initially but
+ // is not remangled when a Chunk_t is returned to the free list
+ // (since it is used to maintain the chunk on the free list).
+ tc->assert_is_mangled();
+ tc->set_size(size);
+ tc->link_prev(NULL);
+ tc->link_next(NULL);
+ TreeList<Chunk_t, FreeList_t>* tl = TreeList<Chunk_t, FreeList_t>::as_TreeList(tc);
+ return tl;
+}
+
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>*
+TreeList<Chunk_t, FreeList_t>::get_better_list(
+ BinaryTreeDictionary<Chunk_t, FreeList_t>* dictionary) {
+ return this;
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::remove_chunk_replace_if_needed(TreeChunk<Chunk_t, FreeList_t>* tc) {
+
+ TreeList<Chunk_t, FreeList_t>* retTL = this;
+ Chunk_t* list = head();
+ assert(!list || list != list->next(), "Chunk on list twice");
+ assert(tc != NULL, "Chunk being removed is NULL");
+ assert(parent() == NULL || this == parent()->left() ||
+ this == parent()->right(), "list is inconsistent");
+ assert(tc->is_free(), "Header is not marked correctly");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+
+ Chunk_t* prevFC = tc->prev();
+ TreeChunk<Chunk_t, FreeList_t>* nextTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(tc->next());
+ assert(list != NULL, "should have at least the target chunk");
+
+ // Is this the first item on the list?
+ if (tc == list) {
+ // The "getChunk..." functions for a TreeList<Chunk_t, FreeList_t> will not return the
+ // first chunk in the list unless it is the last chunk in the list
+ // because the first chunk is also acting as the tree node.
+ // When coalescing happens, however, the first chunk in the a tree
+ // list can be the start of a free range. Free ranges are removed
+ // from the free lists so that they are not available to be
+ // allocated when the sweeper yields (giving up the free list lock)
+ // to allow mutator activity. If this chunk is the first in the
+ // list and is not the last in the list, do the work to copy the
+ // TreeList<Chunk_t, FreeList_t> from the first chunk to the next chunk and update all
+ // the TreeList<Chunk_t, FreeList_t> pointers in the chunks in the list.
+ if (nextTC == NULL) {
+ assert(prevFC == NULL, "Not last chunk in the list");
+ set_tail(NULL);
+ set_head(NULL);
+ } else {
+ // copy embedded list.
+ nextTC->set_embedded_list(tc->embedded_list());
+ retTL = nextTC->embedded_list();
+ // Fix the pointer to the list in each chunk in the list.
+ // This can be slow for a long list. Consider having
+ // an option that does not allow the first chunk on the
+ // list to be coalesced.
+ for (TreeChunk<Chunk_t, FreeList_t>* curTC = nextTC; curTC != NULL;
+ curTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(curTC->next())) {
+ curTC->set_list(retTL);
+ }
+ // Fix the parent to point to the new TreeList<Chunk_t, FreeList_t>.
+ if (retTL->parent() != NULL) {
+ if (this == retTL->parent()->left()) {
+ retTL->parent()->set_left(retTL);
+ } else {
+ assert(this == retTL->parent()->right(), "Parent is incorrect");
+ retTL->parent()->set_right(retTL);
+ }
+ }
+ // Fix the children's parent pointers to point to the
+ // new list.
+ assert(right() == retTL->right(), "Should have been copied");
+ if (retTL->right() != NULL) {
+ retTL->right()->set_parent(retTL);
+ }
+ assert(left() == retTL->left(), "Should have been copied");
+ if (retTL->left() != NULL) {
+ retTL->left()->set_parent(retTL);
+ }
+ retTL->link_head(nextTC);
+ assert(nextTC->is_free(), "Should be a free chunk");
+ }
+ } else {
+ if (nextTC == NULL) {
+ // Removing chunk at tail of list
+ this->link_tail(prevFC);
+ }
+ // Chunk is interior to the list
+ prevFC->link_after(nextTC);
+ }
+
+ // Below this point the embedded TreeList<Chunk_t, FreeList_t> being used for the
+ // tree node may have changed. Don't use "this"
+ // TreeList<Chunk_t, FreeList_t>*.
+ // chunk should still be a free chunk (bit set in _prev)
+ assert(!retTL->head() || retTL->size() == retTL->head()->size(),
+ "Wrong sized chunk in list");
+ debug_only(
+ tc->link_prev(NULL);
+ tc->link_next(NULL);
+ tc->set_list(NULL);
+ bool prev_found = false;
+ bool next_found = false;
+ for (Chunk_t* curFC = retTL->head();
+ curFC != NULL; curFC = curFC->next()) {
+ assert(curFC != tc, "Chunk is still in list");
+ if (curFC == prevFC) {
+ prev_found = true;
+ }
+ if (curFC == nextTC) {
+ next_found = true;
+ }
+ }
+ assert(prevFC == NULL || prev_found, "Chunk was lost from list");
+ assert(nextTC == NULL || next_found, "Chunk was lost from list");
+ assert(retTL->parent() == NULL ||
+ retTL == retTL->parent()->left() ||
+ retTL == retTL->parent()->right(),
+ "list is inconsistent");
+ )
+ retTL->decrement_count();
+
+ assert(tc->is_free(), "Should still be a free chunk");
+ assert(retTL->head() == NULL || retTL->head()->prev() == NULL,
+ "list invariant");
+ assert(retTL->tail() == NULL || retTL->tail()->next() == NULL,
+ "list invariant");
+ return retTL;
+}
+
+template <class Chunk_t, class FreeList_t>
+void TreeList<Chunk_t, FreeList_t>::return_chunk_at_tail(TreeChunk<Chunk_t, FreeList_t>* chunk) {
+ assert(chunk != NULL, "returning NULL chunk");
+ assert(chunk->list() == this, "list should be set for chunk");
+ assert(tail() != NULL, "The tree list is embedded in the first chunk");
+ // which means that the list can never be empty.
+ assert(!this->verify_chunk_in_free_list(chunk), "Double entry");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+
+ Chunk_t* fc = tail();
+ fc->link_after(chunk);
+ this->link_tail(chunk);
+
+ assert(!tail() || size() == tail()->size(), "Wrong sized chunk in list");
+ FreeList_t::increment_count();
+ debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+}
+
+// Add this chunk at the head of the list. "At the head of the list"
+// is defined to be after the chunk pointer to by head(). This is
+// because the TreeList<Chunk_t, FreeList_t> is embedded in the first TreeChunk<Chunk_t, FreeList_t> in the
+// list. See the definition of TreeChunk<Chunk_t, FreeList_t>.
+template <class Chunk_t, class FreeList_t>
+void TreeList<Chunk_t, FreeList_t>::return_chunk_at_head(TreeChunk<Chunk_t, FreeList_t>* chunk) {
+ assert(chunk->list() == this, "list should be set for chunk");
+ assert(head() != NULL, "The tree list is embedded in the first chunk");
+ assert(chunk != NULL, "returning NULL chunk");
+ assert(!this->verify_chunk_in_free_list(chunk), "Double entry");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+
+ Chunk_t* fc = head()->next();
+ if (fc != NULL) {
+ chunk->link_after(fc);
+ } else {
+ assert(tail() == NULL, "List is inconsistent");
+ this->link_tail(chunk);
+ }
+ head()->link_after(chunk);
+ assert(!head() || size() == head()->size(), "Wrong sized chunk in list");
+ FreeList_t::increment_count();
+ debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+}
+
+template <class Chunk_t, class FreeList_t>
+void TreeChunk<Chunk_t, FreeList_t>::assert_is_mangled() const {
+ assert((ZapUnusedHeapArea &&
+ SpaceMangler::is_mangled((HeapWord*) Chunk_t::size_addr()) &&
+ SpaceMangler::is_mangled((HeapWord*) Chunk_t::prev_addr()) &&
+ SpaceMangler::is_mangled((HeapWord*) Chunk_t::next_addr())) ||
+ (size() == 0 && prev() == NULL && next() == NULL),
+ "Space should be clear or mangled");
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::head_as_TreeChunk() {
+ assert(head() == NULL || (TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head())->list() == this),
+ "Wrong type of chunk?");
+ return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head());
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::first_available() {
+ assert(head() != NULL, "The head of the list cannot be NULL");
+ Chunk_t* fc = head()->next();
+ TreeChunk<Chunk_t, FreeList_t>* retTC;
+ if (fc == NULL) {
+ retTC = head_as_TreeChunk();
+ } else {
+ retTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(fc);
+ }
+ assert(retTC->list() == this, "Wrong type of chunk.");
+ return retTC;
+}
+
+// Returns the block with the largest heap address amongst
+// those in the list for this size; potentially slow and expensive,
+// use with caution!
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::largest_address() {
+ assert(head() != NULL, "The head of the list cannot be NULL");
+ Chunk_t* fc = head()->next();
+ TreeChunk<Chunk_t, FreeList_t>* retTC;
+ if (fc == NULL) {
+ retTC = head_as_TreeChunk();
+ } else {
+ // walk down the list and return the one with the highest
+ // heap address among chunks of this size.
+ Chunk_t* last = fc;
+ while (fc->next() != NULL) {
+ if ((HeapWord*)last < (HeapWord*)fc) {
+ last = fc;
+ }
+ fc = fc->next();
+ }
+ retTC = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(last);
+ }
+ assert(retTC->list() == this, "Wrong type of chunk.");
+ return retTC;
+}
+
+template <class Chunk_t, class FreeList_t>
+BinaryTreeDictionary<Chunk_t, FreeList_t>::BinaryTreeDictionary(MemRegion mr) {
+ assert((mr.byte_size() > min_size()), "minimum chunk size");
+
+ reset(mr);
+ assert(root()->left() == NULL, "reset check failed");
+ assert(root()->right() == NULL, "reset check failed");
+ assert(root()->head()->next() == NULL, "reset check failed");
+ assert(root()->head()->prev() == NULL, "reset check failed");
+ assert(total_size() == root()->size(), "reset check failed");
+ assert(total_free_blocks() == 1, "reset check failed");
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::inc_total_size(size_t inc) {
+ _total_size = _total_size + inc;
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::dec_total_size(size_t dec) {
+ _total_size = _total_size - dec;
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(MemRegion mr) {
+ assert((mr.byte_size() > min_size()), "minimum chunk size");
+ set_root(TreeList<Chunk_t, FreeList_t>::as_TreeList(mr.start(), mr.word_size()));
+ set_total_size(mr.word_size());
+ set_total_free_blocks(1);
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(HeapWord* addr, size_t byte_size) {
+ MemRegion mr(addr, heap_word_size(byte_size));
+ reset(mr);
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset() {
+ set_root(NULL);
+ set_total_size(0);
+ set_total_free_blocks(0);
+}
+
+// Get a free block of size at least size from tree, or NULL.
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>*
+BinaryTreeDictionary<Chunk_t, FreeList_t>::get_chunk_from_tree(size_t size)
+{
+ TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
+ TreeChunk<Chunk_t, FreeList_t>* retTC = NULL;
+
+ assert((size >= min_size()), "minimum chunk size");
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+ // starting at the root, work downwards trying to find match.
+ // Remember the last node of size too great or too small.
+ for (prevTL = curTL = root(); curTL != NULL;) {
+ if (curTL->size() == size) { // exact match
+ break;
+ }
+ prevTL = curTL;
+ if (curTL->size() < size) { // proceed to right sub-tree
+ curTL = curTL->right();
+ } else { // proceed to left sub-tree
+ assert(curTL->size() > size, "size inconsistency");
+ curTL = curTL->left();
+ }
+ }
+ if (curTL == NULL) { // couldn't find exact match
+
+ // try and find the next larger size by walking back up the search path
+ for (curTL = prevTL; curTL != NULL;) {
+ if (curTL->size() >= size) break;
+ else curTL = curTL->parent();
+ }
+ assert(curTL == NULL || curTL->count() > 0,
+ "An empty list should not be in the tree");
+ }
+ if (curTL != NULL) {
+ assert(curTL->size() >= size, "size inconsistency");
+
+ curTL = curTL->get_better_list(this);
+
+ retTC = curTL->first_available();
+ assert((retTC != NULL) && (curTL->count() > 0),
+ "A list in the binary tree should not be NULL");
+ assert(retTC->size() >= size,
+ "A chunk of the wrong size was found");
+ remove_chunk_from_tree(retTC);
+ assert(retTC->is_free(), "Header is not marked correctly");
+ }
+
+ if (FLSVerifyDictionary) {
+ verify();
+ }
+ return retTC;
+}
+
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_list(size_t size) const {
+ TreeList<Chunk_t, FreeList_t>* curTL;
+ for (curTL = root(); curTL != NULL;) {
+ if (curTL->size() == size) { // exact match
+ break;
+ }
+
+ if (curTL->size() < size) { // proceed to right sub-tree
+ curTL = curTL->right();
+ } else { // proceed to left sub-tree
+ assert(curTL->size() > size, "size inconsistency");
+ curTL = curTL->left();
+ }
+ }
+ return curTL;
+}
+
+
+template <class Chunk_t, class FreeList_t>
+bool BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_chunk_in_free_list(Chunk_t* tc) const {
+ size_t size = tc->size();
+ TreeList<Chunk_t, FreeList_t>* tl = find_list(size);
+ if (tl == NULL) {
+ return false;
+ } else {
+ return tl->verify_chunk_in_free_list(tc);
+ }
+}
+
+template <class Chunk_t, class FreeList_t>
+Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_largest_dict() const {
+ TreeList<Chunk_t, FreeList_t> *curTL = root();
+ if (curTL != NULL) {
+ while(curTL->right() != NULL) curTL = curTL->right();
+ return curTL->largest_address();
+ } else {
+ return NULL;
+ }
+}
+
+// Remove the current chunk from the tree. If it is not the last
+// chunk in a list on a tree node, just unlink it.
+// If it is the last chunk in the list (the next link is NULL),
+// remove the node and repair the tree.
+template <class Chunk_t, class FreeList_t>
+TreeChunk<Chunk_t, FreeList_t>*
+BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_chunk_from_tree(TreeChunk<Chunk_t, FreeList_t>* tc) {
+ assert(tc != NULL, "Should not call with a NULL chunk");
+ assert(tc->is_free(), "Header is not marked correctly");
+
+ TreeList<Chunk_t, FreeList_t> *newTL, *parentTL;
+ TreeChunk<Chunk_t, FreeList_t>* retTC;
+ TreeList<Chunk_t, FreeList_t>* tl = tc->list();
+ debug_only(
+ bool removing_only_chunk = false;
+ if (tl == _root) {
+ if ((_root->left() == NULL) && (_root->right() == NULL)) {
+ if (_root->count() == 1) {
+ assert(_root->head() == tc, "Should only be this one chunk");
+ removing_only_chunk = true;
+ }
+ }
+ }
+ )
+ assert(tl != NULL, "List should be set");
+ assert(tl->parent() == NULL || tl == tl->parent()->left() ||
+ tl == tl->parent()->right(), "list is inconsistent");
+
+ bool complicated_splice = false;
+
+ retTC = tc;
+ // Removing this chunk can have the side effect of changing the node
+ // (TreeList<Chunk_t, FreeList_t>*) in the tree. If the node is the root, update it.
+ TreeList<Chunk_t, FreeList_t>* replacementTL = tl->remove_chunk_replace_if_needed(tc);
+ assert(tc->is_free(), "Chunk should still be free");
+ assert(replacementTL->parent() == NULL ||
+ replacementTL == replacementTL->parent()->left() ||
+ replacementTL == replacementTL->parent()->right(),
+ "list is inconsistent");
+ if (tl == root()) {
+ assert(replacementTL->parent() == NULL, "Incorrectly replacing root");
+ set_root(replacementTL);
+ }
+#ifdef ASSERT
+ if (tl != replacementTL) {
+ assert(replacementTL->head() != NULL,
+ "If the tree list was replaced, it should not be a NULL list");
+ TreeList<Chunk_t, FreeList_t>* rhl = replacementTL->head_as_TreeChunk()->list();
+ TreeList<Chunk_t, FreeList_t>* rtl =
+ TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(replacementTL->tail())->list();
+ assert(rhl == replacementTL, "Broken head");
+ assert(rtl == replacementTL, "Broken tail");
+ assert(replacementTL->size() == tc->size(), "Broken size");
+ }
+#endif
+
+ // Does the tree need to be repaired?
+ if (replacementTL->count() == 0) {
+ assert(replacementTL->head() == NULL &&
+ replacementTL->tail() == NULL, "list count is incorrect");
+ // Find the replacement node for the (soon to be empty) node being removed.
+ // if we have a single (or no) child, splice child in our stead
+ if (replacementTL->left() == NULL) {
+ // left is NULL so pick right. right may also be NULL.
+ newTL = replacementTL->right();
+ debug_only(replacementTL->clear_right();)
+ } else if (replacementTL->right() == NULL) {
+ // right is NULL
+ newTL = replacementTL->left();
+ debug_only(replacementTL->clear_left();)
+ } else { // we have both children, so, by patriarchal convention,
+ // my replacement is least node in right sub-tree
+ complicated_splice = true;
+ newTL = remove_tree_minimum(replacementTL->right());
+ assert(newTL != NULL && newTL->left() == NULL &&
+ newTL->right() == NULL, "sub-tree minimum exists");
+ }
+ // newTL is the replacement for the (soon to be empty) node.
+ // newTL may be NULL.
+ // should verify; we just cleanly excised our replacement
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+ // first make newTL my parent's child
+ if ((parentTL = replacementTL->parent()) == NULL) {
+ // newTL should be root
+ assert(tl == root(), "Incorrectly replacing root");
+ set_root(newTL);
+ if (newTL != NULL) {
+ newTL->clear_parent();
+ }
+ } else if (parentTL->right() == replacementTL) {
+ // replacementTL is a right child
+ parentTL->set_right(newTL);
+ } else { // replacementTL is a left child
+ assert(parentTL->left() == replacementTL, "should be left child");
+ parentTL->set_left(newTL);
+ }
+ debug_only(replacementTL->clear_parent();)
+ if (complicated_splice) { // we need newTL to get replacementTL's
+ // two children
+ assert(newTL != NULL &&
+ newTL->left() == NULL && newTL->right() == NULL,
+ "newTL should not have encumbrances from the past");
+ // we'd like to assert as below:
+ // assert(replacementTL->left() != NULL && replacementTL->right() != NULL,
+ // "else !complicated_splice");
+ // ... however, the above assertion is too strong because we aren't
+ // guaranteed that replacementTL->right() is still NULL.
+ // Recall that we removed
+ // the right sub-tree minimum from replacementTL.
+ // That may well have been its right
+ // child! So we'll just assert half of the above:
+ assert(replacementTL->left() != NULL, "else !complicated_splice");
+ newTL->set_left(replacementTL->left());
+ newTL->set_right(replacementTL->right());
+ debug_only(
+ replacementTL->clear_right();
+ replacementTL->clear_left();
+ )
+ }
+ assert(replacementTL->right() == NULL &&
+ replacementTL->left() == NULL &&
+ replacementTL->parent() == NULL,
+ "delete without encumbrances");
+ }
+
+ assert(total_size() >= retTC->size(), "Incorrect total size");
+ dec_total_size(retTC->size()); // size book-keeping
+ assert(total_free_blocks() > 0, "Incorrect total count");
+ set_total_free_blocks(total_free_blocks() - 1);
+
+ assert(retTC != NULL, "null chunk?");
+ assert(retTC->prev() == NULL && retTC->next() == NULL,
+ "should return without encumbrances");
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+ assert(!removing_only_chunk || _root == NULL, "root should be NULL");
+ return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(retTC);
+}
+
+// Remove the leftmost node (lm) in the tree and return it.
+// If lm has a right child, link it to the left node of
+// the parent of lm.
+template <class Chunk_t, class FreeList_t>
+TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_tree_minimum(TreeList<Chunk_t, FreeList_t>* tl) {
+ assert(tl != NULL && tl->parent() != NULL, "really need a proper sub-tree");
+ // locate the subtree minimum by walking down left branches
+ TreeList<Chunk_t, FreeList_t>* curTL = tl;
+ for (; curTL->left() != NULL; curTL = curTL->left());
+ // obviously curTL now has at most one child, a right child
+ if (curTL != root()) { // Should this test just be removed?
+ TreeList<Chunk_t, FreeList_t>* parentTL = curTL->parent();
+ if (parentTL->left() == curTL) { // curTL is a left child
+ parentTL->set_left(curTL->right());
+ } else {
+ // If the list tl has no left child, then curTL may be
+ // the right child of parentTL.
+ assert(parentTL->right() == curTL, "should be a right child");
+ parentTL->set_right(curTL->right());
+ }
+ } else {
+ // The only use of this method would not pass the root of the
+ // tree (as indicated by the assertion above that the tree list
+ // has a parent) but the specification does not explicitly exclude the
+ // passing of the root so accommodate it.
+ set_root(NULL);
+ }
+ debug_only(
+ curTL->clear_parent(); // Test if this needs to be cleared
+ curTL->clear_right(); // recall, above, left child is already null
+ )
+ // we just excised a (non-root) node, we should still verify all tree invariants
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+ return curTL;
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::insert_chunk_in_tree(Chunk_t* fc) {
+ TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
+ size_t size = fc->size();
+
+ assert((size >= min_size()),
+ SIZE_FORMAT " is too small to be a TreeChunk<Chunk_t, FreeList_t> " SIZE_FORMAT,
+ size, min_size());
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+
+ fc->clear_next();
+ fc->link_prev(NULL);
+
+ // work down from the _root, looking for insertion point
+ for (prevTL = curTL = root(); curTL != NULL;) {
+ if (curTL->size() == size) // exact match
+ break;
+ prevTL = curTL;
+ if (curTL->size() > size) { // follow left branch
+ curTL = curTL->left();
+ } else { // follow right branch
+ assert(curTL->size() < size, "size inconsistency");
+ curTL = curTL->right();
+ }
+ }
+ TreeChunk<Chunk_t, FreeList_t>* tc = TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(fc);
+ // This chunk is being returned to the binary tree. Its embedded
+ // TreeList<Chunk_t, FreeList_t> should be unused at this point.
+ tc->initialize();
+ if (curTL != NULL) { // exact match
+ tc->set_list(curTL);
+ curTL->return_chunk_at_tail(tc);
+ } else { // need a new node in tree
+ tc->clear_next();
+ tc->link_prev(NULL);
+ TreeList<Chunk_t, FreeList_t>* newTL = TreeList<Chunk_t, FreeList_t>::as_TreeList(tc);
+ assert(((TreeChunk<Chunk_t, FreeList_t>*)tc)->list() == newTL,
+ "List was not initialized correctly");
+ if (prevTL == NULL) { // we are the only tree node
+ assert(root() == NULL, "control point invariant");
+ set_root(newTL);
+ } else { // insert under prevTL ...
+ if (prevTL->size() < size) { // am right child
+ assert(prevTL->right() == NULL, "control point invariant");
+ prevTL->set_right(newTL);
+ } else { // am left child
+ assert(prevTL->size() > size && prevTL->left() == NULL, "cpt pt inv");
+ prevTL->set_left(newTL);
+ }
+ }
+ }
+ assert(tc->list() != NULL, "Tree list should be set");
+
+ inc_total_size(size);
+ // Method 'total_size_in_tree' walks through the every block in the
+ // tree, so it can cause significant performance loss if there are
+ // many blocks in the tree
+ assert(!FLSVerifyDictionary || total_size_in_tree(root()) == total_size(), "_total_size inconsistency");
+ set_total_free_blocks(total_free_blocks() + 1);
+ if (FLSVerifyDictionary) {
+ verify_tree();
+ }
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::max_chunk_size() const {
+ verify_par_locked();
+ TreeList<Chunk_t, FreeList_t>* tc = root();
+ if (tc == NULL) return 0;
+ for (; tc->right() != NULL; tc = tc->right());
+ return tc->size();
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_list_length(TreeList<Chunk_t, FreeList_t>* tl) const {
+ size_t res;
+ res = tl->count();
+#ifdef ASSERT
+ size_t cnt;
+ Chunk_t* tc = tl->head();
+ for (cnt = 0; tc != NULL; tc = tc->next(), cnt++);
+ assert(res == cnt, "The count is not being maintained correctly");
+#endif
+ return res;
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_size_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
+ if (tl == NULL)
+ return 0;
+ return (tl->size() * total_list_length(tl)) +
+ total_size_in_tree(tl->left()) +
+ total_size_in_tree(tl->right());
+}
+
+template <class Chunk_t, class FreeList_t>
+double BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_of_squared_block_sizes(TreeList<Chunk_t, FreeList_t>* const tl) const {
+ if (tl == NULL) {
+ return 0.0;
+ }
+ double size = (double)(tl->size());
+ double curr = size * size * total_list_length(tl);
+ curr += sum_of_squared_block_sizes(tl->left());
+ curr += sum_of_squared_block_sizes(tl->right());
+ return curr;
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_free_blocks_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
+ if (tl == NULL)
+ return 0;
+ return total_list_length(tl) +
+ total_free_blocks_in_tree(tl->left()) +
+ total_free_blocks_in_tree(tl->right());
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::num_free_blocks() const {
+ assert(total_free_blocks_in_tree(root()) == total_free_blocks(),
+ "_total_free_blocks inconsistency");
+ return total_free_blocks();
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
+ if (tl == NULL)
+ return 0;
+ return 1 + MAX2(tree_height_helper(tl->left()),
+ tree_height_helper(tl->right()));
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height() const {
+ return tree_height_helper(root());
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
+ if (tl == NULL) {
+ return 0;
+ }
+ return 1 + total_nodes_helper(tl->left()) +
+ total_nodes_helper(tl->right());
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
+ return total_nodes_helper(root());
+}
+
+// Searches the tree for a chunk that ends at the
+// specified address.
+template <class Chunk_t, class FreeList_t>
+class EndTreeSearchClosure : public DescendTreeSearchClosure<Chunk_t, FreeList_t> {
+ HeapWord* _target;
+ Chunk_t* _found;
+
+ public:
+ EndTreeSearchClosure(HeapWord* target) : _target(target), _found(NULL) {}
+ bool do_list(FreeList_t* fl) {
+ Chunk_t* item = fl->head();
+ while (item != NULL) {
+ if (item->end() == (uintptr_t*) _target) {
+ _found = item;
+ return true;
+ }
+ item = item->next();
+ }
+ return false;
+ }
+ Chunk_t* found() { return _found; }
+};
+
+template <class Chunk_t, class FreeList_t>
+Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_chunk_ends_at(HeapWord* target) const {
+ EndTreeSearchClosure<Chunk_t, FreeList_t> etsc(target);
+ bool found_target = etsc.do_tree(root());
+ assert(found_target || etsc.found() == NULL, "Consistency check");
+ assert(!found_target || etsc.found() != NULL, "Consistency check");
+ return etsc.found();
+}
+
+// Closures and methods for calculating total bytes returned to the
+// free lists in the tree.
+#ifndef PRODUCT
+template <class Chunk_t, class FreeList_t>
+class InitializeDictReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
+ public:
+ void do_list(FreeList_t* fl) {
+ fl->set_returned_bytes(0);
+ }
+};
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::initialize_dict_returned_bytes() {
+ InitializeDictReturnedBytesClosure<Chunk_t, FreeList_t> idrb;
+ idrb.do_tree(root());
+}
+
+template <class Chunk_t, class FreeList_t>
+class ReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
+ size_t _dict_returned_bytes;
+ public:
+ ReturnedBytesClosure() { _dict_returned_bytes = 0; }
+ void do_list(FreeList_t* fl) {
+ _dict_returned_bytes += fl->returned_bytes();
+ }
+ size_t dict_returned_bytes() { return _dict_returned_bytes; }
+};
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_dict_returned_bytes() {
+ ReturnedBytesClosure<Chunk_t, FreeList_t> rbc;
+ rbc.do_tree(root());
+
+ return rbc.dict_returned_bytes();
+}
+
+// Count the number of entries in the tree.
+template <class Chunk_t, class FreeList_t>
+class treeCountClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
+ public:
+ uint count;
+ treeCountClosure(uint c) { count = c; }
+ void do_list(FreeList_t* fl) {
+ count++;
+ }
+};
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_count() {
+ treeCountClosure<Chunk_t, FreeList_t> ctc(0);
+ ctc.do_tree(root());
+ return ctc.count;
+}
+
+template <class Chunk_t, class FreeList_t>
+Mutex* BinaryTreeDictionary<Chunk_t, FreeList_t>::par_lock() const {
+ return _lock;
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_par_lock(Mutex* lock) {
+ _lock = lock;
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_par_locked() const {
+#ifdef ASSERT
+ Thread* my_thread = Thread::current();
+ if (my_thread->is_GC_task_thread()) {
+ assert(par_lock() != NULL, "Should be using locking?");
+ assert_lock_strong(par_lock());
+ }
+#endif // ASSERT
+}
+#endif // PRODUCT
+
+// Print summary statistics
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::report_statistics(outputStream* st) const {
+ verify_par_locked();
+ st->print_cr("Statistics for BinaryTreeDictionary:");
+ st->print_cr("------------------------------------");
+ size_t total_size = total_chunk_size(debug_only(NULL));
+ size_t free_blocks = num_free_blocks();
+ st->print_cr("Total Free Space: " SIZE_FORMAT, total_size);
+ st->print_cr("Max Chunk Size: " SIZE_FORMAT, max_chunk_size());
+ st->print_cr("Number of Blocks: " SIZE_FORMAT, free_blocks);
+ if (free_blocks > 0) {
+ st->print_cr("Av. Block Size: " SIZE_FORMAT, total_size/free_blocks);
+ }
+ st->print_cr("Tree Height: " SIZE_FORMAT, tree_height());
+}
+
+template <class Chunk_t, class FreeList_t>
+class PrintFreeListsClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
+ outputStream* _st;
+ int _print_line;
+
+ public:
+ PrintFreeListsClosure(outputStream* st) {
+ _st = st;
+ _print_line = 0;
+ }
+ void do_list(FreeList_t* fl) {
+ if (++_print_line >= 40) {
+ FreeList_t::print_labels_on(_st, "size");
+ _print_line = 0;
+ }
+ fl->print_on(_st);
+ size_t sz = fl->size();
+ for (Chunk_t* fc = fl->head(); fc != NULL;
+ fc = fc->next()) {
+ _st->print_cr("\t[" PTR_FORMAT "," PTR_FORMAT ") %s",
+ p2i(fc), p2i((HeapWord*)fc + sz),
+ fc->cantCoalesce() ? "\t CC" : "");
+ }
+ }
+};
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_free_lists(outputStream* st) const {
+
+ FreeList_t::print_labels_on(st, "size");
+ PrintFreeListsClosure<Chunk_t, FreeList_t> pflc(st);
+ pflc.do_tree(root());
+}
+
+// Verify the following tree invariants:
+// . _root has no parent
+// . parent and child point to each other
+// . each node's key correctly related to that of its child(ren)
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree() const {
+ guarantee(root() == NULL || total_free_blocks() == 0 ||
+ total_size() != 0, "_total_size shouldn't be 0?");
+ guarantee(root() == NULL || root()->parent() == NULL, "_root shouldn't have parent");
+ verify_tree_helper(root());
+}
+
+template <class Chunk_t, class FreeList_t>
+size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_prev_free_ptrs(TreeList<Chunk_t, FreeList_t>* tl) {
+ size_t ct = 0;
+ for (Chunk_t* curFC = tl->head(); curFC != NULL; curFC = curFC->next()) {
+ ct++;
+ assert(curFC->prev() == NULL || curFC->prev()->is_free(),
+ "Chunk should be free");
+ }
+ return ct;
+}
+
+// Note: this helper is recursive rather than iterative, so use with
+// caution on very deep trees; and watch out for stack overflow errors;
+// In general, to be used only for debugging.
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
+ if (tl == NULL)
+ return;
+ guarantee(tl->size() != 0, "A list must has a size");
+ guarantee(tl->left() == NULL || tl->left()->parent() == tl,
+ "parent<-/->left");
+ guarantee(tl->right() == NULL || tl->right()->parent() == tl,
+ "parent<-/->right");;
+ guarantee(tl->left() == NULL || tl->left()->size() < tl->size(),
+ "parent !> left");
+ guarantee(tl->right() == NULL || tl->right()->size() > tl->size(),
+ "parent !< left");
+ guarantee(tl->head() == NULL || tl->head()->is_free(), "!Free");
+ guarantee(tl->head() == NULL || tl->head_as_TreeChunk()->list() == tl,
+ "list inconsistency");
+ guarantee(tl->count() > 0 || (tl->head() == NULL && tl->tail() == NULL),
+ "list count is inconsistent");
+ guarantee(tl->count() > 1 || tl->head() == tl->tail(),
+ "list is incorrectly constructed");
+ size_t count = verify_prev_free_ptrs(tl);
+ guarantee(count == (size_t)tl->count(), "Node count is incorrect");
+ if (tl->head() != NULL) {
+ tl->head_as_TreeChunk()->verify_tree_chunk_list();
+ }
+ verify_tree_helper(tl->left());
+ verify_tree_helper(tl->right());
+}
+
+template <class Chunk_t, class FreeList_t>
+void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify() const {
+ verify_tree();
+ guarantee(total_size() == total_size_in_tree(root()), "Total Size inconsistency");
+}
+
+#endif // SHARE_VM_MEMORY_BINARYTREEDICTIONARY_INLINE_HPP
--- a/src/hotspot/share/memory/filemap.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/memory/filemap.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -96,7 +96,7 @@
va_list ap;
va_start(ap, msg);
MetaspaceShared::set_archive_loading_failed();
- if (PrintSharedArchiveAndExit && _validating_classpath_entry_table) {
+ if (PrintSharedArchiveAndExit && _validating_shared_path_table) {
// If we are doing PrintSharedArchiveAndExit and some of the classpath entries
// do not validate, we can still continue "limping" to validate the remaining
// entries. No need to quit.
@@ -188,9 +188,9 @@
_max_heap_size = MaxHeapSize;
_narrow_klass_base = Universe::narrow_klass_base();
_narrow_klass_shift = Universe::narrow_klass_shift();
- _classpath_entry_table_size = mapinfo->_classpath_entry_table_size;
- _classpath_entry_table = mapinfo->_classpath_entry_table;
- _classpath_entry_size = mapinfo->_classpath_entry_size;
+ _shared_path_table_size = mapinfo->_shared_path_table_size;
+ _shared_path_table = mapinfo->_shared_path_table;
+ _shared_path_entry_size = mapinfo->_shared_path_entry_size;
// The following fields are for sanity checks for whether this archive
// will function correctly with this JVM and the bootclasspath it's
@@ -231,12 +231,16 @@
strcpy(_name->data(), name);
}
-bool SharedClassPathEntry::validate() {
+bool SharedClassPathEntry::validate(bool is_class_path) {
struct stat st;
const char* name = this->name();
bool ok = true;
log_info(class, path)("checking shared classpath entry: %s", name);
- if (os::stat(name, &st) != 0) {
+ if (os::stat(name, &st) != 0 && is_class_path) {
+ // If the archived module path entry does not exist at runtime, it is not fatal
+ // (no need to invalid the shared archive) because the shared runtime visibility check
+ // filters out any archived module classes that do not have a matching runtime
+ // module path location.
FileMapInfo::fail_continue("Required classpath entry does not exist: %s", name);
ok = false;
} else if (is_dir()) {
@@ -266,7 +270,7 @@
it->push(&_manifest);
}
-void FileMapInfo::allocate_classpath_entry_table() {
+void FileMapInfo::allocate_shared_path_table() {
assert(DumpSharedSpaces, "Sanity");
Thread* THREAD = Thread::current();
@@ -279,12 +283,13 @@
size_t entry_size = SharedClassUtil::shared_class_path_entry_size(); // assert ( should be 8 byte aligned??)
int num_boot_classpath_entries = ClassLoader::num_boot_classpath_entries();
int num_app_classpath_entries = ClassLoader::num_app_classpath_entries();
- int num_entries = num_boot_classpath_entries + num_app_classpath_entries;
+ int num_module_path_entries = ClassLoader::num_module_path_entries();
+ int num_entries = num_boot_classpath_entries + num_app_classpath_entries + num_module_path_entries;
size_t bytes = entry_size * num_entries;
- _classpath_entry_table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
- _classpath_entry_table_size = num_entries;
- _classpath_entry_size = entry_size;
+ _shared_path_table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
+ _shared_path_table_size = num_entries;
+ _shared_path_entry_size = entry_size;
// 1. boot class path
int i = 0;
@@ -292,7 +297,7 @@
while (cpe != NULL) {
const char* type = ((cpe == jrt) ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir"));
log_info(class, path)("add main shared path (%s) %s", type, cpe->name());
- SharedClassPathEntry* ent = shared_classpath(i);
+ SharedClassPathEntry* ent = shared_path(i);
ent->init(cpe->name(), THREAD);
if (cpe != jrt) { // No need to do jimage.
EXCEPTION_MARK; // The following call should never throw, but would exit VM on error.
@@ -308,41 +313,66 @@
ClassPathEntry *acpe = ClassLoader::app_classpath_entries();
while (acpe != NULL) {
log_info(class, path)("add app shared path %s", acpe->name());
- SharedClassPathEntry* ent = shared_classpath(i);
+ SharedClassPathEntry* ent = shared_path(i);
ent->init(acpe->name(), THREAD);
EXCEPTION_MARK;
SharedClassUtil::update_shared_classpath(acpe, ent, THREAD);
acpe = acpe->next();
- i ++;
+ i++;
}
- assert(i == num_entries, "number of app class path entry mismatch");
+
+ // 3. module path
+ ClassPathEntry *mpe = ClassLoader::module_path_entries();
+ while (mpe != NULL) {
+ log_info(class, path)("add module path %s",mpe->name());
+ SharedClassPathEntry* ent = shared_path(i);
+ ent->init(mpe->name(), THREAD);
+ EXCEPTION_MARK;
+ SharedClassUtil::update_shared_classpath(mpe, ent, THREAD);
+ mpe = mpe->next();
+ i++;
+ }
+ assert(i == num_entries, "number of shared path entry mismatch");
}
-bool FileMapInfo::validate_classpath_entry_table() {
- _validating_classpath_entry_table = true;
+// This function should only be called during run time with UseSharedSpaces enabled.
+bool FileMapInfo::validate_shared_path_table() {
+ _validating_shared_path_table = true;
+
+ _shared_path_table = _header->_shared_path_table;
+ _shared_path_entry_size = _header->_shared_path_entry_size;
+ _shared_path_table_size = _header->_shared_path_table_size;
- int count = _header->_classpath_entry_table_size;
+ // Note: _app_module_paths_start_index may not have a valid value if the UseAppCDS flag
+ // wasn't enabled during dump time. Therefore, we need to use the smaller of
+ // _shared_path_table_size and _app_module_paths_start_index for the _app_module_paths_start_index.
+ FileMapHeaderExt* header = (FileMapHeaderExt*)FileMapInfo::current_info()->header();
+ int module_paths_start_index = (header->_app_module_paths_start_index >= _shared_path_table_size) ?
+ _shared_path_table_size : header->_app_module_paths_start_index;
- _classpath_entry_table = _header->_classpath_entry_table;
- _classpath_entry_size = _header->_classpath_entry_size;
- _classpath_entry_table_size = _header->_classpath_entry_table_size;
+ int count = _shared_path_table_size;
for (int i=0; i<count; i++) {
- if (shared_classpath(i)->validate()) {
- log_info(class, path)("ok");
+ if (i < module_paths_start_index) {
+ if (shared_path(i)->validate()) {
+ log_info(class, path)("ok");
+ }
+ } else if (i >= module_paths_start_index) {
+ if (shared_path(i)->validate(false /* not a class path entry */)) {
+ log_info(class, path)("ok");
+ }
} else if (!PrintSharedArchiveAndExit) {
- _validating_classpath_entry_table = false;
- _classpath_entry_table = NULL;
- _classpath_entry_table_size = 0;
+ _validating_shared_path_table = false;
+ _shared_path_table = NULL;
+ _shared_path_table_size = 0;
return false;
}
}
- _validating_classpath_entry_table = false;
+ _validating_shared_path_table = false;
return true;
}
-
// Read the FileMapInfo information from the file.
bool FileMapInfo::init_from_file(int fd) {
@@ -925,18 +955,18 @@
}
void FileMapInfo::metaspace_pointers_do(MetaspaceClosure* it) {
- it->push(&_classpath_entry_table);
- for (int i=0; i<_classpath_entry_table_size; i++) {
- shared_classpath(i)->metaspace_pointers_do(it);
+ it->push(&_shared_path_table);
+ for (int i=0; i<_shared_path_table_size; i++) {
+ shared_path(i)->metaspace_pointers_do(it);
}
}
FileMapInfo* FileMapInfo::_current_info = NULL;
-Array<u8>* FileMapInfo::_classpath_entry_table = NULL;
-int FileMapInfo::_classpath_entry_table_size = 0;
-size_t FileMapInfo::_classpath_entry_size = 0x1234baad;
-bool FileMapInfo::_validating_classpath_entry_table = false;
+Array<u8>* FileMapInfo::_shared_path_table = NULL;
+int FileMapInfo::_shared_path_table_size = 0;
+size_t FileMapInfo::_shared_path_entry_size = 0x1234baad;
+bool FileMapInfo::_validating_shared_path_table = false;
// Open the shared archive file, read and validate the header
// information (version, boot classpath, etc.). If initialization
@@ -946,7 +976,7 @@
// Validation of the archive is done in two steps:
//
// [1] validate_header() - done here. This checks the header, including _paths_misc_info.
-// [2] validate_classpath_entry_table - this is done later, because the table is in the RW
+// [2] validate_shared_path_table - this is done later, because the table is in the RW
// region of the archive, which is not mapped yet.
bool FileMapInfo::initialize() {
assert(UseSharedSpaces, "UseSharedSpaces expected.");
@@ -980,6 +1010,7 @@
return crc;
}
+// This function should only be called during run time with UseSharedSpaces enabled.
bool FileMapInfo::FileMapHeader::validate() {
if (VerifySharedSpaces && compute_crc() != _crc) {
fail_continue("Header checksum verification failed.");
--- a/src/hotspot/share/memory/filemap.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/memory/filemap.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -53,7 +53,7 @@
public:
void init(const char* name, TRAPS);
void metaspace_pointers_do(MetaspaceClosure* it);
- bool validate();
+ bool validate(bool is_class_path = true);
// The _timestamp only gets set for jar files and "modules" jimage.
bool is_jar_or_bootimage() {
@@ -85,10 +85,10 @@
size_t _file_offset;
private:
- static Array<u8>* _classpath_entry_table;
- static int _classpath_entry_table_size;
- static size_t _classpath_entry_size;
- static bool _validating_classpath_entry_table;
+ static Array<u8>* _shared_path_table;
+ static int _shared_path_table_size;
+ static size_t _shared_path_entry_size;
+ static bool _validating_shared_path_table;
// FileMapHeader describes the shared space data in the file to be
// mapped. This structure gets written to a file. It is not a class, so
@@ -153,7 +153,7 @@
// checking the validity of the archive and is deallocated after the archive is loaded.
//
// Note that the _paths_misc_info does NOT include information for JAR files
- // that existed during dump time. Their information is stored in _classpath_entry_table.
+ // that existed during dump time. Their information is stored in _shared_path_table.
int _paths_misc_info_size;
// The following is a table of all the class path entries that were used
@@ -167,9 +167,9 @@
// FIXME -- if JAR files in the tail of the list were specified but not used during dumping,
// they should be removed from this table, to save space and to avoid spurious
// loading failures during runtime.
- int _classpath_entry_table_size;
- size_t _classpath_entry_size;
- Array<u8>* _classpath_entry_table;
+ int _shared_path_table_size;
+ size_t _shared_path_entry_size;
+ Array<u8>* _shared_path_table;
char* region_addr(int idx);
@@ -270,25 +270,26 @@
// Stop CDS sharing and unmap CDS regions.
static void stop_sharing_and_unmap(const char* msg);
- static void allocate_classpath_entry_table();
- bool validate_classpath_entry_table();
+ static void allocate_shared_path_table();
+ bool validate_shared_path_table();
- static SharedClassPathEntry* shared_classpath(int index) {
+ static SharedClassPathEntry* shared_path(int index) {
if (index < 0) {
return NULL;
}
- assert(index < _classpath_entry_table_size, "sanity");
- char* p = (char*)_classpath_entry_table->data();
- p += _classpath_entry_size * index;
+ assert(index < _shared_path_table_size, "sanity");
+ char* p = (char*)_shared_path_table->data();
+ p += _shared_path_entry_size * index;
return (SharedClassPathEntry*)p;
}
- static const char* shared_classpath_name(int index) {
+
+ static const char* shared_path_name(int index) {
assert(index >= 0, "Sanity");
- return shared_classpath(index)->name();
+ return shared_path(index)->name();
}
- static int get_number_of_share_classpaths() {
- return _classpath_entry_table_size;
+ static int get_number_of_shared_paths() {
+ return _shared_path_table_size;
}
private:
--- a/src/hotspot/share/memory/freeList.cpp Tue Apr 17 08:54:17 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,336 +0,0 @@
-/*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
- * 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/shared/collectedHeap.hpp"
-#include "memory/freeList.hpp"
-#include "memory/metachunk.hpp"
-#include "runtime/globals.hpp"
-#include "runtime/mutex.hpp"
-#include "runtime/vmThread.hpp"
-#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/cms/freeChunk.hpp"
-#endif // INCLUDE_ALL_GCS
-
-// Free list. A FreeList is used to access a linked list of chunks
-// of space in the heap. The head and tail are maintained so that
-// items can be (as in the current implementation) added at the
-// at the tail of the list and removed from the head of the list to
-// maintain a FIFO queue.
-
-template <class Chunk>
-FreeList<Chunk>::FreeList() :
- _head(NULL), _tail(NULL)
-#ifdef ASSERT
- , _protecting_lock(NULL)
-#endif
-{
- _size = 0;
- _count = 0;
-}
-
-template <class Chunk>
-void FreeList<Chunk>::link_head(Chunk* v) {
- assert_proper_lock_protection();
- set_head(v);
- // If this method is not used (just set the head instead),
- // this check can be avoided.
- if (v != NULL) {
- v->link_prev(NULL);
- }
-}
-
-
-
-template <class Chunk>
-void FreeList<Chunk>::reset() {
- // Don't set the _size to 0 because this method is
- // used with a existing list that has a size but which has
- // been emptied.
- // Don't clear the _protecting_lock of an existing list.
- set_count(0);
- set_head(NULL);
- set_tail(NULL);
-}
-
-template <class Chunk>
-void FreeList<Chunk>::initialize() {
-#ifdef ASSERT
- // Needed early because it might be checked in other initializing code.
- set_protecting_lock(NULL);
-#endif
- reset();
- set_size(0);
-}
-
-template <class Chunk_t>
-Chunk_t* FreeList<Chunk_t>::get_chunk_at_head() {
- assert_proper_lock_protection();
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- Chunk_t* fc = head();
- if (fc != NULL) {
- Chunk_t* nextFC = fc->next();
- if (nextFC != NULL) {
- // The chunk fc being removed has a "next". Set the "next" to the
- // "prev" of fc.
- nextFC->link_prev(NULL);
- } else { // removed tail of list
- link_tail(NULL);
- }
- link_head(nextFC);
- decrement_count();
- }
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- return fc;
-}
-
-
-template <class Chunk>
-void FreeList<Chunk>::getFirstNChunksFromList(size_t n, FreeList<Chunk>* fl) {
- assert_proper_lock_protection();
- assert(fl->count() == 0, "Precondition");
- if (count() > 0) {
- int k = 1;
- fl->set_head(head()); n--;
- Chunk* tl = head();
- while (tl->next() != NULL && n > 0) {
- tl = tl->next(); n--; k++;
- }
- assert(tl != NULL, "Loop Inv.");
-
- // First, fix up the list we took from.
- Chunk* new_head = tl->next();
- set_head(new_head);
- set_count(count() - k);
- if (new_head == NULL) {
- set_tail(NULL);
- } else {
- new_head->link_prev(NULL);
- }
- // Now we can fix up the tail.
- tl->link_next(NULL);
- // And return the result.
- fl->set_tail(tl);
- fl->set_count(k);
- }
-}
-
-// Remove this chunk from the list
-template <class Chunk>
-void FreeList<Chunk>::remove_chunk(Chunk*fc) {
- assert_proper_lock_protection();
- assert(head() != NULL, "Remove from empty list");
- assert(fc != NULL, "Remove a NULL chunk");
- assert(size() == fc->size(), "Wrong list");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-
- Chunk* prevFC = fc->prev();
- Chunk* nextFC = fc->next();
- if (nextFC != NULL) {
- // The chunk fc being removed has a "next". Set the "next" to the
- // "prev" of fc.
- nextFC->link_prev(prevFC);
- } else { // removed tail of list
- link_tail(prevFC);
- }
- if (prevFC == NULL) { // removed head of list
- link_head(nextFC);
- assert(nextFC == NULL || nextFC->prev() == NULL,
- "Prev of head should be NULL");
- } else {
- prevFC->link_next(nextFC);
- assert(tail() != prevFC || prevFC->next() == NULL,
- "Next of tail should be NULL");
- }
- decrement_count();
- assert(((head() == NULL) + (tail() == NULL) + (count() == 0)) % 3 == 0,
- "H/T/C Inconsistency");
- // clear next and prev fields of fc, debug only
- NOT_PRODUCT(
- fc->link_prev(NULL);
- fc->link_next(NULL);
- )
- assert(fc->is_free(), "Should still be a free chunk");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- assert(head() == NULL || head()->size() == size(), "wrong item on list");
- assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
-}
-
-// Add this chunk at the head of the list.
-template <class Chunk>
-void FreeList<Chunk>::return_chunk_at_head(Chunk* chunk, bool record_return) {
- assert_proper_lock_protection();
- assert(chunk != NULL, "insert a NULL chunk");
- assert(size() == chunk->size(), "Wrong size");
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
-
- Chunk* oldHead = head();
- assert(chunk != oldHead, "double insertion");
- chunk->link_after(oldHead);
- link_head(chunk);
- if (oldHead == NULL) { // only chunk in list
- assert(tail() == NULL, "inconsistent FreeList");
- link_tail(chunk);
- }
- increment_count(); // of # of chunks in list
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- assert(head() == NULL || head()->size() == size(), "wrong item on list");
- assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
-}
-
-template <class Chunk>
-void FreeList<Chunk>::return_chunk_at_head(Chunk* chunk) {
- assert_proper_lock_protection();
- return_chunk_at_head(chunk, true);
-}
-
-// Add this chunk at the tail of the list.
-template <class Chunk>
-void FreeList<Chunk>::return_chunk_at_tail(Chunk* chunk, bool record_return) {
- assert_proper_lock_protection();
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- assert(chunk != NULL, "insert a NULL chunk");
- assert(size() == chunk->size(), "wrong size");
-
- Chunk* oldTail = tail();
- assert(chunk != oldTail, "double insertion");
- if (oldTail != NULL) {
- oldTail->link_after(chunk);
- } else { // only chunk in list
- assert(head() == NULL, "inconsistent FreeList");
- link_head(chunk);
- }
- link_tail(chunk);
- increment_count(); // of # of chunks in list
- assert(head() == NULL || head()->prev() == NULL, "list invariant");
- assert(tail() == NULL || tail()->next() == NULL, "list invariant");
- assert(head() == NULL || head()->size() == size(), "wrong item on list");
- assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
-}
-
-template <class Chunk>
-void FreeList<Chunk>::return_chunk_at_tail(Chunk* chunk) {
- return_chunk_at_tail(chunk, true);
-}
-
-template <class Chunk>
-void FreeList<Chunk>::prepend(FreeList<Chunk>* fl) {
- assert_proper_lock_protection();
- if (fl->count() > 0) {
- if (count() == 0) {
- set_head(fl->head());
- set_tail(fl->tail());
- set_count(fl->count());
- } else {
- // Both are non-empty.
- Chunk* fl_tail = fl->tail();
- Chunk* this_head = head();
- assert(fl_tail->next() == NULL, "Well-formedness of fl");
- fl_tail->link_next(this_head);
- this_head->link_prev(fl_tail);
- set_head(fl->head());
- set_count(count() + fl->count());
- }
- fl->set_head(NULL);
- fl->set_tail(NULL);
- fl->set_count(0);
- }
-}
-
-// verify_chunk_in_free_lists() is used to verify that an item is in this free list.
-// It is used as a debugging aid.
-template <class Chunk>
-bool FreeList<Chunk>::verify_chunk_in_free_list(Chunk* fc) const {
- // This is an internal consistency check, not part of the check that the
- // chunk is in the free lists.
- guarantee(fc->size() == size(), "Wrong list is being searched");
- Chunk* curFC = head();
- while (curFC) {
- // This is an internal consistency check.
- guarantee(size() == curFC->size(), "Chunk is in wrong list.");
- if (fc == curFC) {
- return true;
- }
- curFC = curFC->next();
- }
- return false;
-}
-
-#ifdef ASSERT
-template <class Chunk>
-void FreeList<Chunk>::assert_proper_lock_protection_work() const {
- // Nothing to do if the list has no assigned protecting lock
- if (protecting_lock() == NULL) {
- return;
- }
-
- Thread* thr = Thread::current();
- if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
- // assert that we are holding the freelist lock
- } else if (thr->is_GC_task_thread()) {
- assert(protecting_lock()->owned_by_self(), "FreeList RACE DETECTED");
- } else if (thr->is_Java_thread()) {
- assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
- } else {
- ShouldNotReachHere(); // unaccounted thread type?
- }
-}
-#endif
-
-// Print the "label line" for free list stats.
-template <class Chunk>
-void FreeList<Chunk>::print_labels_on(outputStream* st, const char* c) {
- st->print("%16s\t", c);
- st->print("%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t"
- "%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "\n",
- "bfrsurp", "surplus", "desired", "prvSwep", "bfrSwep",
- "count", "cBirths", "cDeaths", "sBirths", "sDeaths");
-}
-
-// Print the AllocationStats for the given free list. If the second argument
-// to the call is a non-null string, it is printed in the first column;
-// otherwise, if the argument is null (the default), then the size of the
-// (free list) block is printed in the first column.
-template <class Chunk_t>
-void FreeList<Chunk_t>::print_on(outputStream* st, const char* c) const {
- if (c != NULL) {
- st->print("%16s", c);
- } else {
- st->print(SIZE_FORMAT_W(16), size());
- }
-}
-
-template class FreeList<Metablock>;
-template class FreeList<Metachunk>;
-#if INCLUDE_ALL_GCS
-template class FreeList<FreeChunk>;
-#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/share/memory/freeList.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/memory/freeList.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,10 +25,6 @@
#ifndef SHARE_VM_MEMORY_FREELIST_HPP
#define SHARE_VM_MEMORY_FREELIST_HPP
-#include "gc/cms/allocationStats.hpp"
-
-class CompactibleFreeListSpace;
-
// A class for maintaining a free list of Chunk's. The FreeList
// maintains a the structure of the list (head, tail, etc.) plus
// statistics for allocations from the list. The links between items
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/freeList.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * 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_MEMORY_FREELIST_INLINE_HPP
+#define SHARE_MEMORY_FREELIST_INLINE_HPP
+
+#include "gc/shared/collectedHeap.hpp"
+#include "memory/freeList.hpp"
+#include "memory/metachunk.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/mutex.hpp"
+#include "runtime/vmThread.hpp"
+#include "utilities/macros.hpp"
+
+// Free list. A FreeList is used to access a linked list of chunks
+// of space in the heap. The head and tail are maintained so that
+// items can be (as in the current implementation) added at the
+// at the tail of the list and removed from the head of the list to
+// maintain a FIFO queue.
+
+template <class Chunk>
+FreeList<Chunk>::FreeList() :
+ _head(NULL), _tail(NULL)
+#ifdef ASSERT
+ , _protecting_lock(NULL)
+#endif
+{
+ _size = 0;
+ _count = 0;
+}
+
+template <class Chunk>
+void FreeList<Chunk>::link_head(Chunk* v) {
+ assert_proper_lock_protection();
+ set_head(v);
+ // If this method is not used (just set the head instead),
+ // this check can be avoided.
+ if (v != NULL) {
+ v->link_prev(NULL);
+ }
+}
+
+
+
+template <class Chunk>
+void FreeList<Chunk>::reset() {
+ // Don't set the _size to 0 because this method is
+ // used with a existing list that has a size but which has
+ // been emptied.
+ // Don't clear the _protecting_lock of an existing list.
+ set_count(0);
+ set_head(NULL);
+ set_tail(NULL);
+}
+
+template <class Chunk>
+void FreeList<Chunk>::initialize() {
+#ifdef ASSERT
+ // Needed early because it might be checked in other initializing code.
+ set_protecting_lock(NULL);
+#endif
+ reset();
+ set_size(0);
+}
+
+template <class Chunk_t>
+Chunk_t* FreeList<Chunk_t>::get_chunk_at_head() {
+ assert_proper_lock_protection();
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ Chunk_t* fc = head();
+ if (fc != NULL) {
+ Chunk_t* nextFC = fc->next();
+ if (nextFC != NULL) {
+ // The chunk fc being removed has a "next". Set the "next" to the
+ // "prev" of fc.
+ nextFC->link_prev(NULL);
+ } else { // removed tail of list
+ link_tail(NULL);
+ }
+ link_head(nextFC);
+ decrement_count();
+ }
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ return fc;
+}
+
+
+template <class Chunk>
+void FreeList<Chunk>::getFirstNChunksFromList(size_t n, FreeList<Chunk>* fl) {
+ assert_proper_lock_protection();
+ assert(fl->count() == 0, "Precondition");
+ if (count() > 0) {
+ int k = 1;
+ fl->set_head(head()); n--;
+ Chunk* tl = head();
+ while (tl->next() != NULL && n > 0) {
+ tl = tl->next(); n--; k++;
+ }
+ assert(tl != NULL, "Loop Inv.");
+
+ // First, fix up the list we took from.
+ Chunk* new_head = tl->next();
+ set_head(new_head);
+ set_count(count() - k);
+ if (new_head == NULL) {
+ set_tail(NULL);
+ } else {
+ new_head->link_prev(NULL);
+ }
+ // Now we can fix up the tail.
+ tl->link_next(NULL);
+ // And return the result.
+ fl->set_tail(tl);
+ fl->set_count(k);
+ }
+}
+
+// Remove this chunk from the list
+template <class Chunk>
+void FreeList<Chunk>::remove_chunk(Chunk*fc) {
+ assert_proper_lock_protection();
+ assert(head() != NULL, "Remove from empty list");
+ assert(fc != NULL, "Remove a NULL chunk");
+ assert(size() == fc->size(), "Wrong list");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+
+ Chunk* prevFC = fc->prev();
+ Chunk* nextFC = fc->next();
+ if (nextFC != NULL) {
+ // The chunk fc being removed has a "next". Set the "next" to the
+ // "prev" of fc.
+ nextFC->link_prev(prevFC);
+ } else { // removed tail of list
+ link_tail(prevFC);
+ }
+ if (prevFC == NULL) { // removed head of list
+ link_head(nextFC);
+ assert(nextFC == NULL || nextFC->prev() == NULL,
+ "Prev of head should be NULL");
+ } else {
+ prevFC->link_next(nextFC);
+ assert(tail() != prevFC || prevFC->next() == NULL,
+ "Next of tail should be NULL");
+ }
+ decrement_count();
+ assert(((head() == NULL) + (tail() == NULL) + (count() == 0)) % 3 == 0,
+ "H/T/C Inconsistency");
+ // clear next and prev fields of fc, debug only
+ NOT_PRODUCT(
+ fc->link_prev(NULL);
+ fc->link_next(NULL);
+ )
+ assert(fc->is_free(), "Should still be a free chunk");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ assert(head() == NULL || head()->size() == size(), "wrong item on list");
+ assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
+}
+
+// Add this chunk at the head of the list.
+template <class Chunk>
+void FreeList<Chunk>::return_chunk_at_head(Chunk* chunk, bool record_return) {
+ assert_proper_lock_protection();
+ assert(chunk != NULL, "insert a NULL chunk");
+ assert(size() == chunk->size(), "Wrong size");
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+
+ Chunk* oldHead = head();
+ assert(chunk != oldHead, "double insertion");
+ chunk->link_after(oldHead);
+ link_head(chunk);
+ if (oldHead == NULL) { // only chunk in list
+ assert(tail() == NULL, "inconsistent FreeList");
+ link_tail(chunk);
+ }
+ increment_count(); // of # of chunks in list
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ assert(head() == NULL || head()->size() == size(), "wrong item on list");
+ assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
+}
+
+template <class Chunk>
+void FreeList<Chunk>::return_chunk_at_head(Chunk* chunk) {
+ assert_proper_lock_protection();
+ return_chunk_at_head(chunk, true);
+}
+
+// Add this chunk at the tail of the list.
+template <class Chunk>
+void FreeList<Chunk>::return_chunk_at_tail(Chunk* chunk, bool record_return) {
+ assert_proper_lock_protection();
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ assert(chunk != NULL, "insert a NULL chunk");
+ assert(size() == chunk->size(), "wrong size");
+
+ Chunk* oldTail = tail();
+ assert(chunk != oldTail, "double insertion");
+ if (oldTail != NULL) {
+ oldTail->link_after(chunk);
+ } else { // only chunk in list
+ assert(head() == NULL, "inconsistent FreeList");
+ link_head(chunk);
+ }
+ link_tail(chunk);
+ increment_count(); // of # of chunks in list
+ assert(head() == NULL || head()->prev() == NULL, "list invariant");
+ assert(tail() == NULL || tail()->next() == NULL, "list invariant");
+ assert(head() == NULL || head()->size() == size(), "wrong item on list");
+ assert(tail() == NULL || tail()->size() == size(), "wrong item on list");
+}
+
+template <class Chunk>
+void FreeList<Chunk>::return_chunk_at_tail(Chunk* chunk) {
+ return_chunk_at_tail(chunk, true);
+}
+
+template <class Chunk>
+void FreeList<Chunk>::prepend(FreeList<Chunk>* fl) {
+ assert_proper_lock_protection();
+ if (fl->count() > 0) {
+ if (count() == 0) {
+ set_head(fl->head());
+ set_tail(fl->tail());
+ set_count(fl->count());
+ } else {
+ // Both are non-empty.
+ Chunk* fl_tail = fl->tail();
+ Chunk* this_head = head();
+ assert(fl_tail->next() == NULL, "Well-formedness of fl");
+ fl_tail->link_next(this_head);
+ this_head->link_prev(fl_tail);
+ set_head(fl->head());
+ set_count(count() + fl->count());
+ }
+ fl->set_head(NULL);
+ fl->set_tail(NULL);
+ fl->set_count(0);
+ }
+}
+
+// verify_chunk_in_free_lists() is used to verify that an item is in this free list.
+// It is used as a debugging aid.
+template <class Chunk>
+bool FreeList<Chunk>::verify_chunk_in_free_list(Chunk* fc) const {
+ // This is an internal consistency check, not part of the check that the
+ // chunk is in the free lists.
+ guarantee(fc->size() == size(), "Wrong list is being searched");
+ Chunk* curFC = head();
+ while (curFC) {
+ // This is an internal consistency check.
+ guarantee(size() == curFC->size(), "Chunk is in wrong list.");
+ if (fc == curFC) {
+ return true;
+ }
+ curFC = curFC->next();
+ }
+ return false;
+}
+
+#ifdef ASSERT
+template <class Chunk>
+void FreeList<Chunk>::assert_proper_lock_protection_work() const {
+ // Nothing to do if the list has no assigned protecting lock
+ if (protecting_lock() == NULL) {
+ return;
+ }
+
+ Thread* thr = Thread::current();
+ if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
+ // assert that we are holding the freelist lock
+ } else if (thr->is_GC_task_thread()) {
+ assert(protecting_lock()->owned_by_self(), "FreeList RACE DETECTED");
+ } else if (thr->is_Java_thread()) {
+ assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
+ } else {
+ ShouldNotReachHere(); // unaccounted thread type?
+ }
+}
+#endif
+
+// Print the "label line" for free list stats.
+template <class Chunk>
+void FreeList<Chunk>::print_labels_on(outputStream* st, const char* c) {
+ st->print("%16s\t", c);
+ st->print("%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t"
+ "%14s\t" "%14s\t" "%14s\t" "%14s\t" "%14s\t" "\n",
+ "bfrsurp", "surplus", "desired", "prvSwep", "bfrSwep",
+ "count", "cBirths", "cDeaths", "sBirths", "sDeaths");
+}
+
+// Print the AllocationStats for the given free list. If the second argument
+// to the call is a non-null string, it is printed in the first column;
+// otherwise, if the argument is null (the default), then the size of the
+// (free list) block is printed in the first column.
+template <class Chunk_t>
+void FreeList<Chunk_t>::print_on(outputStream* st, const char* c) const {
+ if (c != NULL) {
+ st->print("%16s", c);
+ } else {
+ st->print(SIZE_FORMAT_W(16), size());
+ }
+}
+
+#endif // SHARE_MEMORY_FREELIST_INLINE_HPP
--- a/src/hotspot/share/memory/heapInspection.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/memory/heapInspection.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -27,7 +27,6 @@
#include "classfile/moduleEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc/shared/collectedHeap.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "memory/heapInspection.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
@@ -35,9 +34,6 @@
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
#include "utilities/stack.inline.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/parallel/parallelScavengeHeap.hpp"
-#endif // INCLUDE_ALL_GCS
// HeapInspection
--- a/src/hotspot/share/memory/metaspace.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/memory/metaspace.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,9 +28,9 @@
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.hpp"
-#include "memory/binaryTreeDictionary.hpp"
+#include "memory/binaryTreeDictionary.inline.hpp"
#include "memory/filemap.hpp"
-#include "memory/freeList.hpp"
+#include "memory/freeList.inline.hpp"
#include "memory/metachunk.hpp"
#include "memory/metaspace.hpp"
#include "memory/metaspaceGCThresholdUpdater.hpp"
@@ -5342,4 +5342,3 @@
out->medium_chunk_word_size = ClassMediumChunk;
}
}
-
--- a/src/hotspot/share/memory/metaspaceShared.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/memory/metaspaceShared.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1619,7 +1619,6 @@
void MetaspaceShared::prepare_for_dumping() {
Arguments::check_unsupported_dumping_properties();
ClassLoader::initialize_shared_path();
- FileMapInfo::allocate_classpath_entry_table();
}
// Preload classes from a list, populate the shared spaces and dump to a
@@ -2001,7 +2000,7 @@
(md_base = mapinfo->map_region(md, &md_top)) != NULL &&
(od_base = mapinfo->map_region(od, &od_top)) != NULL &&
(image_alignment == (size_t)os::vm_allocation_granularity()) &&
- mapinfo->validate_classpath_entry_table()) {
+ mapinfo->validate_shared_path_table()) {
// Success -- set up MetaspaceObj::_shared_metaspace_{base,top} for
// fast checking in MetaspaceShared::is_in_shared_metaspace() and
// MetaspaceObj::is_shared().
--- a/src/hotspot/share/memory/universe.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/memory/universe.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -689,6 +689,8 @@
return status;
}
+ SystemDictionary::initialize_oop_storage();
+
Metaspace::global_initialize();
// Initialize performance counters for metaspaces
--- a/src/hotspot/share/oops/accessBackend.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/oops/accessBackend.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -316,7 +316,7 @@
reinterpret_cast<jlong*>((oopDesc*)dst),
align_object_size(size) / HeapWordsPerLong);
// Clear the header
- dst->init_mark();
+ dst->init_mark_raw();
}
#endif // SHARE_VM_RUNTIME_ACCESSBACKEND_INLINE_HPP
--- a/src/hotspot/share/oops/instanceKlass.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/oops/instanceKlass.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1901,7 +1901,7 @@
}
void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) {
- assert(class_loader_data()->is_alive(is_alive), "this klass should be live");
+ assert(class_loader_data()->is_alive(), "this klass should be live");
if (is_interface()) {
if (ClassUnloading) {
Klass* impl = implementor();
@@ -3407,14 +3407,8 @@
}
}
-oop InstanceKlass::klass_holder_phantom() {
- oop* addr;
- if (is_anonymous()) {
- addr = _java_mirror.ptr_raw();
- } else {
- addr = &class_loader_data()->_class_loader;
- }
- return RootAccess<IN_CONCURRENT_ROOT | ON_PHANTOM_OOP_REF>::oop_load(addr);
+oop InstanceKlass::holder_phantom() const {
+ return class_loader_data()->holder_phantom();
}
#ifdef ASSERT
--- a/src/hotspot/share/oops/instanceKlass.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/oops/instanceKlass.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -646,10 +646,10 @@
return is_anonymous() ? java_mirror() : class_loader();
}
- // Load the klass_holder as a phantom. This is useful when a weak Klass
+ // Load the klass's holder as a phantom. This is useful when a weak Klass
// pointer has been "peeked" and then must be kept alive before it may
// be used safely.
- oop klass_holder_phantom();
+ oop holder_phantom() const;
bool is_contended() const {
return (_misc_flags & _misc_is_contended) != 0;
--- a/src/hotspot/share/oops/klass.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/oops/klass.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -150,7 +150,7 @@
int _vtable_len;
private:
- // This is an index into FileMapHeader::_classpath_entry_table[], to
+ // This is an index into FileMapHeader::_shared_path_table[], to
// associate this class with the JAR file where it's loaded from during
// dump time. If a class is not loaded from the shared archive, this field is
// -1.
@@ -166,7 +166,7 @@
#endif
// The _archived_mirror is set at CDS dump time pointing to the cached mirror
// in the open archive heap region when archiving java object is supported.
- CDS_JAVA_HEAP_ONLY(narrowOop _archived_mirror);
+ CDS_JAVA_HEAP_ONLY(narrowOop _archived_mirror;)
friend class SharedClassUtil;
protected:
--- a/src/hotspot/share/oops/objArrayOop.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/oops/objArrayOop.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -31,13 +31,13 @@
oop objArrayOopDesc::atomic_compare_exchange_oop(int index, oop exchange_value,
oop compare_value) {
- volatile HeapWord* dest;
+ ptrdiff_t offs;
if (UseCompressedOops) {
- dest = (HeapWord*)obj_at_addr<narrowOop>(index);
+ offs = objArrayOopDesc::obj_at_offset<narrowOop>(index);
} else {
- dest = (HeapWord*)obj_at_addr<oop>(index);
+ offs = objArrayOopDesc::obj_at_offset<oop>(index);
}
- return HeapAccess<>::oop_atomic_cmpxchg(exchange_value, dest, compare_value);
+ return HeapAccess<IN_HEAP_ARRAY>::oop_atomic_cmpxchg_at(exchange_value, as_oop(), offs, compare_value);
}
Klass* objArrayOopDesc::element_klass() {
--- a/src/hotspot/share/oops/oop.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/oops/oop.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -134,7 +134,7 @@
if (ignore_mark_word) {
return true;
}
- if (obj->mark() != NULL) {
+ if (obj->mark_raw() != NULL) {
return true;
}
return !SafepointSynchronize::is_at_safepoint();
--- a/src/hotspot/share/oops/oop.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/oops/oop.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -63,17 +63,21 @@
} _metadata;
public:
- markOop mark() const { return _mark; }
- markOop* mark_addr() const { return (markOop*) &_mark; }
+ inline markOop mark() const;
+ inline markOop mark_raw() const;
+ inline markOop* mark_addr_raw() const;
- void set_mark(volatile markOop m) { _mark = m; }
+ inline void set_mark(volatile markOop m);
+ inline void set_mark_raw(volatile markOop m);
inline void release_set_mark(markOop m);
inline markOop cas_set_mark(markOop new_mark, markOop old_mark);
+ inline markOop cas_set_mark_raw(markOop new_mark, markOop old_mark);
// Used only to re-initialize the mark word (e.g., of promoted
// objects during a GC) -- requires a valid klass pointer
inline void init_mark();
+ inline void init_mark_raw();
inline Klass* klass() const;
inline Klass* klass_or_null() const volatile;
@@ -237,6 +241,7 @@
inline bool is_locked() const;
inline bool is_unlocked() const;
inline bool has_bias_pattern() const;
+ inline bool has_bias_pattern_raw() const;
// asserts and guarantees
static bool is_oop(oop obj, bool ignore_mark_word = false);
@@ -323,9 +328,9 @@
unsigned int new_hash(juint seed);
// marks are forwarded to stack when object is locked
- inline bool has_displaced_mark() const;
- inline markOop displaced_mark() const;
- inline void set_displaced_mark(markOop m);
+ inline bool has_displaced_mark_raw() const;
+ inline markOop displaced_mark_raw() const;
+ inline void set_displaced_mark_raw(markOop m);
static bool has_klass_gap();
--- a/src/hotspot/share/oops/oop.inline.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/oops/oop.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,11 +44,35 @@
// Implementation of all inlined member functions defined in oop.hpp
// We need a separate file to avoid circular references
+markOop oopDesc::mark() const {
+ return HeapAccess<MO_VOLATILE>::load_at(as_oop(), mark_offset_in_bytes());
+}
+
+markOop oopDesc::mark_raw() const {
+ return _mark;
+}
+
+markOop* oopDesc::mark_addr_raw() const {
+ return (markOop*) &_mark;
+}
+
+void oopDesc::set_mark(volatile markOop m) {
+ HeapAccess<MO_VOLATILE>::store_at(as_oop(), mark_offset_in_bytes(), m);
+}
+
+void oopDesc::set_mark_raw(volatile markOop m) {
+ _mark = m;
+}
+
void oopDesc::release_set_mark(markOop m) {
- OrderAccess::release_store(&_mark, m);
+ HeapAccess<MO_RELEASE>::store_at(as_oop(), mark_offset_in_bytes(), m);
}
markOop oopDesc::cas_set_mark(markOop new_mark, markOop old_mark) {
+ return HeapAccess<>::atomic_cmpxchg_at(new_mark, as_oop(), mark_offset_in_bytes(), old_mark);
+}
+
+markOop oopDesc::cas_set_mark_raw(markOop new_mark, markOop old_mark) {
return Atomic::cmpxchg(new_mark, &_mark, old_mark);
}
@@ -56,6 +80,10 @@
set_mark(markOopDesc::prototype_for_object(this));
}
+void oopDesc::init_mark_raw() {
+ set_mark_raw(markOopDesc::prototype_for_object(this));
+}
+
Klass* oopDesc::klass() const {
if (UseCompressedClassPointers) {
return Klass::decode_klass_not_null(_metadata._compressed_klass);
@@ -281,16 +309,20 @@
return mark()->has_bias_pattern();
}
+bool oopDesc::has_bias_pattern_raw() const {
+ return mark_raw()->has_bias_pattern();
+}
+
// Used only for markSweep, scavenging
bool oopDesc::is_gc_marked() const {
- return mark()->is_marked();
+ return mark_raw()->is_marked();
}
// Used by scavengers
bool oopDesc::is_forwarded() const {
// The extra heap check is needed since the obj might be locked, in which case the
// mark would point to a stack location and have the sentinel bit cleared
- return mark()->is_marked();
+ return mark_raw()->is_marked();
}
// Used by scavengers
@@ -304,7 +336,7 @@
"forwarding archive object");
markOop m = markOopDesc::encode_pointer_as_mark(p);
assert(m->decode_pointer() == p, "encoding must be reversable");
- set_mark(m);
+ set_mark_raw(m);
}
// Used by parallel scavengers
@@ -315,12 +347,12 @@
"forwarding to something not in heap");
markOop m = markOopDesc::encode_pointer_as_mark(p);
assert(m->decode_pointer() == p, "encoding must be reversable");
- return cas_set_mark(m, compare) == compare;
+ return cas_set_mark_raw(m, compare) == compare;
}
#if INCLUDE_ALL_GCS
oop oopDesc::forward_to_atomic(oop p) {
- markOop oldMark = mark();
+ markOop oldMark = mark_raw();
markOop forwardPtrMark = markOopDesc::encode_pointer_as_mark(p);
markOop curMark;
@@ -328,7 +360,7 @@
assert(sizeof(markOop) == sizeof(intptr_t), "CAS below requires this.");
while (!oldMark->is_marked()) {
- curMark = Atomic::cmpxchg(forwardPtrMark, &_mark, oldMark);
+ curMark = cas_set_mark_raw(forwardPtrMark, oldMark);
assert(is_forwarded(), "object should have been forwarded");
if (curMark == oldMark) {
return NULL;
@@ -346,25 +378,25 @@
// The forwardee is used when copying during scavenge and mark-sweep.
// It does need to clear the low two locking- and GC-related bits.
oop oopDesc::forwardee() const {
- return (oop) mark()->decode_pointer();
+ return (oop) mark_raw()->decode_pointer();
}
// The following method needs to be MT safe.
uint oopDesc::age() const {
assert(!is_forwarded(), "Attempt to read age from forwarded mark");
- if (has_displaced_mark()) {
- return displaced_mark()->age();
+ if (has_displaced_mark_raw()) {
+ return displaced_mark_raw()->age();
} else {
- return mark()->age();
+ return mark_raw()->age();
}
}
void oopDesc::incr_age() {
assert(!is_forwarded(), "Attempt to increment age of forwarded mark");
- if (has_displaced_mark()) {
- set_displaced_mark(displaced_mark()->incr_age());
+ if (has_displaced_mark_raw()) {
+ set_displaced_mark_raw(displaced_mark_raw()->incr_age());
} else {
- set_mark(mark()->incr_age());
+ set_mark_raw(mark_raw()->incr_age());
}
}
@@ -465,16 +497,16 @@
}
}
-bool oopDesc::has_displaced_mark() const {
- return mark()->has_displaced_mark_helper();
+bool oopDesc::has_displaced_mark_raw() const {
+ return mark_raw()->has_displaced_mark_helper();
}
-markOop oopDesc::displaced_mark() const {
- return mark()->displaced_mark_helper();
+markOop oopDesc::displaced_mark_raw() const {
+ return mark_raw()->displaced_mark_helper();
}
-void oopDesc::set_displaced_mark(markOop m) {
- mark()->set_displaced_mark_helper(m);
+void oopDesc::set_displaced_mark_raw(markOop m) {
+ mark_raw()->set_displaced_mark_helper(m);
}
#endif // SHARE_VM_OOPS_OOP_INLINE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/oops/weakHandle.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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/systemDictionary.hpp"
+#include "gc/shared/oopStorage.hpp"
+#include "oops/access.inline.hpp"
+#include "oops/oop.hpp"
+#include "oops/weakHandle.inline.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/ostream.hpp"
+
+template <> OopStorage* WeakHandle<vm_class_loader_data>::get_storage() {
+ return SystemDictionary::vm_weak_oop_storage();
+}
+
+template <WeakHandleType T>
+WeakHandle<T> WeakHandle<T>::create(Handle obj) {
+ assert(obj() != NULL, "no need to create weak null oop");
+ oop* oop_addr = get_storage()->allocate();
+ if (oop_addr == NULL) {
+ vm_exit_out_of_memory(sizeof(oop*), OOM_MALLOC_ERROR, "Unable to create new weak oop handle in OopStorage");
+ }
+ // Create WeakHandle with address returned and store oop into it.
+ RootAccess<ON_PHANTOM_OOP_REF>::oop_store(oop_addr, obj());
+ return WeakHandle(oop_addr);
+}
+
+template <WeakHandleType T>
+void WeakHandle<T>::release() const {
+ // Only release if the pointer to the object has been created.
+ if (_obj != NULL) {
+ // Clear the WeakHandle. For class loader data race, the handle may not have
+ // been previously cleared by GC.
+ RootAccess<ON_PHANTOM_OOP_REF>::oop_store(_obj, (oop)NULL);
+ get_storage()->release(_obj);
+ }
+}
+
+template <WeakHandleType T>
+void WeakHandle<T>::print() const { print_on(tty); }
+
+template <WeakHandleType T>
+void WeakHandle<T>::print_on(outputStream* st) const {
+ st->print("WeakHandle: " PTR_FORMAT, p2i(peek()));
+}
+
+// Provide instantiation.
+template class WeakHandle<vm_class_loader_data>;
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/oops/weakHandle.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_OOPS_WEAKHANDLE_HPP
+#define SHARE_VM_OOPS_WEAKHANDLE_HPP
+
+#include "oops/oop.hpp"
+#include "runtime/handles.hpp"
+
+class outputStream;
+class OopStorage;
+
+// A WeakHandle is a pointer to an oop that is stored in an OopStorage that is
+// processed weakly by GC. The runtime structures that point to the oop must
+// either peek or resolve the oop, the latter will keep the oop alive for
+// the GC cycle. The runtime structures that reference the oop must test
+// if the value is NULL. If it is NULL, it has been cleaned out by GC.
+// This is the vm version of jweak but has different GC lifetimes and policies,
+// depending on the type.
+
+enum WeakHandleType { vm_class_loader_data, vm_string };
+
+template <WeakHandleType T>
+class WeakHandle {
+ public:
+
+ private:
+ oop* _obj;
+
+ WeakHandle(oop* w) : _obj(w) {}
+ static OopStorage* get_storage();
+ public:
+ WeakHandle() : _obj(NULL) {} // needed for init
+
+ static WeakHandle create(Handle obj);
+ inline oop resolve() const;
+ inline oop peek() const;
+ void release() const;
+ bool is_null() const { return _obj == NULL; }
+
+ void print() const;
+ void print_on(outputStream* st) const;
+};
+
+#endif // SHARE_VM_OOPS_WEAKHANDLE_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/oops/weakHandle.inline.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_OOPS_WEAKHANDLE_INLINE_HPP
+#define SHARE_VM_OOPS_WEAKHANDLE_INLINE_HPP
+
+#include "oops/weakHandle.hpp"
+#include "oops/access.inline.hpp"
+
+template <WeakHandleType T>
+oop WeakHandle<T>::resolve() const {
+ assert(!is_null(), "Must be created");
+ return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(_obj);
+}
+
+template <WeakHandleType T>
+oop WeakHandle<T>::peek() const {
+ assert(!is_null(), "Must be created");
+ return RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(_obj);
+}
+
+#endif // SHARE_VM_OOPS_WEAKHANDLE_INLINE_HPP
--- a/src/hotspot/share/opto/compile.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/opto/compile.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -73,6 +73,9 @@
#include "runtime/timer.hpp"
#include "utilities/align.hpp"
#include "utilities/copy.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1ThreadLocalData.hpp"
+#endif // INCLUDE_ALL_GCS
// -------------------- Compile::mach_constant_base_node -----------------------
@@ -3752,7 +3755,7 @@
void Compile::verify_barriers() {
if (UseG1GC) {
// Verify G1 pre-barriers
- const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active());
+ const int marking_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
ResourceArea *area = Thread::current()->resource_area();
Unique_Node_List visited(area);
--- a/src/hotspot/share/opto/escape.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/opto/escape.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -37,6 +37,9 @@
#include "opto/phaseX.hpp"
#include "opto/movenode.hpp"
#include "opto/rootnode.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1ThreadLocalData.hpp"
+#endif // INCLUDE_ALL_GCS
ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
_nodes(C->comp_arena(), C->unique(), C->unique(), NULL),
@@ -543,12 +546,10 @@
Node* tls = get_addp_base(adr);
if (tls->Opcode() == Op_ThreadLocal) {
int offs = (int)igvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot);
- if (offs == in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_buf())) {
+ if (offs == in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())) {
break; // G1 pre barrier previous oop value store.
}
- if (offs == in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf())) {
+ if (offs == in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())) {
break; // G1 post barrier card address store.
}
}
--- a/src/hotspot/share/opto/graphKit.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/opto/graphKit.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -48,6 +48,9 @@
#include "opto/runtime.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/sharedRuntime.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1ThreadLocalData.hpp"
+#endif // INCLUDE_ALL_GCS
//----------------------------GraphKit-----------------------------------------
// Main utility constructor.
@@ -1559,7 +1562,7 @@
Node* pre_val,
BasicType bt) {
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
set_control(ctl);
switch (bs->kind()) {
case BarrierSet::G1BarrierSet:
@@ -1576,7 +1579,7 @@
}
bool GraphKit::can_move_pre_barrier() const {
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
switch (bs->kind()) {
case BarrierSet::G1BarrierSet:
return true; // Can move it if no safepoint
@@ -1598,7 +1601,7 @@
Node* val,
BasicType bt,
bool use_precise) {
- BarrierSet* bs = Universe::heap()->barrier_set();
+ BarrierSet* bs = BarrierSet::barrier_set();
set_control(ctl);
switch (bs->kind()) {
case BarrierSet::G1BarrierSet:
@@ -3811,7 +3814,7 @@
#define __ ideal.
bool GraphKit::use_ReduceInitialCardMarks() {
- BarrierSet *bs = Universe::heap()->barrier_set();
+ BarrierSet *bs = BarrierSet::barrier_set();
return bs->is_a(BarrierSet::CardTableBarrierSet)
&& barrier_set_cast<CardTableBarrierSet>(bs)->can_elide_tlab_store_barriers()
&& ReduceInitialCardMarks;
@@ -3882,7 +3885,7 @@
Node* cast = __ CastPX(__ ctrl(), adr);
// Divide by card size
- assert(Universe::heap()->barrier_set()->is_a(BarrierSet::CardTableBarrierSet),
+ assert(BarrierSet::barrier_set()->is_a(BarrierSet::CardTableBarrierSet),
"Only one we handle so far.");
Node* card_offset = __ URShiftX( cast, __ ConI(CardTable::card_shift) );
@@ -4081,12 +4084,9 @@
assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 4 || in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "flag width");
// Offsets into the thread
- const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + // 648
- SATBMarkQueue::byte_offset_of_active());
- const int index_offset = in_bytes(JavaThread::satb_mark_queue_offset() + // 656
- SATBMarkQueue::byte_offset_of_index());
- const int buffer_offset = in_bytes(JavaThread::satb_mark_queue_offset() + // 652
- SATBMarkQueue::byte_offset_of_buf());
+ const int marking_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
+ const int index_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset());
+ const int buffer_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset());
// Now the actual pointers into the thread
Node* marking_adr = __ AddP(no_base, tls, __ ConX(marking_offset));
@@ -4286,10 +4286,8 @@
const TypeFunc *tf = OptoRuntime::g1_wb_post_Type();
// Offsets into the thread
- const int index_offset = in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_index());
- const int buffer_offset = in_bytes(JavaThread::dirty_card_queue_offset() +
- DirtyCardQueue::byte_offset_of_buf());
+ const int index_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset());
+ const int buffer_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset());
// Pointers into the thread
--- a/src/hotspot/share/opto/macro.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/opto/macro.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -47,6 +47,9 @@
#include "opto/subnode.hpp"
#include "opto/type.hpp"
#include "runtime/sharedRuntime.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1ThreadLocalData.hpp"
+#endif // INCLUDE_ALL_GCS
//
@@ -292,8 +295,7 @@
cmpx->is_Cmp() && cmpx->in(2) == intcon(0) &&
cmpx->in(1)->is_Load()) {
Node* adr = cmpx->in(1)->as_Load()->in(MemNode::Address);
- const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() +
- SATBMarkQueue::byte_offset_of_active());
+ const int marking_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset());
if (adr->is_AddP() && adr->in(AddPNode::Base) == top() &&
adr->in(AddPNode::Address)->Opcode() == Op_ThreadLocal &&
adr->in(AddPNode::Offset) == MakeConX(marking_offset)) {
--- a/src/hotspot/share/precompiled/precompiled.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/precompiled/precompiled.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -84,11 +84,6 @@
# include "compiler/disassembler.hpp"
# include "compiler/methodLiveness.hpp"
# include "compiler/oopMap.hpp"
-# include "gc/cms/allocationStats.hpp"
-# include "gc/cms/gSpaceCounters.hpp"
-# include "gc/parallel/immutableSpace.hpp"
-# include "gc/parallel/mutableSpace.hpp"
-# include "gc/parallel/spaceCounters.hpp"
# include "gc/serial/cSpaceCounters.hpp"
# include "gc/serial/defNewGeneration.hpp"
# include "gc/shared/adaptiveSizePolicy.hpp"
@@ -292,9 +287,11 @@
# include "jvmci/jvmci_globals.hpp"
#endif // INCLUDE_JVMCI
#if INCLUDE_ALL_GCS
+# include "gc/cms/allocationStats.hpp"
# include "gc/cms/compactibleFreeListSpace.hpp"
# include "gc/cms/concurrentMarkSweepGeneration.hpp"
# include "gc/cms/freeChunk.hpp"
+# include "gc/cms/gSpaceCounters.hpp"
# include "gc/cms/parOopClosures.hpp"
# include "gc/cms/promotionInfo.hpp"
# include "gc/cms/yieldingWorkgroup.hpp"
@@ -305,6 +302,8 @@
# include "gc/g1/ptrQueue.hpp"
# include "gc/g1/satbMarkQueue.hpp"
# include "gc/parallel/gcAdaptivePolicyCounters.hpp"
+# include "gc/parallel/immutableSpace.hpp"
+# include "gc/parallel/mutableSpace.hpp"
# include "gc/parallel/objectStartArray.hpp"
# include "gc/parallel/parMarkBitMap.hpp"
# include "gc/parallel/parallelScavengeHeap.hpp"
@@ -315,6 +314,7 @@
# include "gc/parallel/psOldGen.hpp"
# include "gc/parallel/psVirtualspace.hpp"
# include "gc/parallel/psYoungGen.hpp"
+# include "gc/parallel/spaceCounters.hpp"
# include "gc/shared/gcPolicyCounters.hpp"
# include "gc/shared/plab.hpp"
#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/share/prims/jvmtiTagMap.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/prims/jvmtiTagMap.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,7 +28,6 @@
#define SHARE_VM_PRIMS_JVMTITAGMAP_HPP
#include "gc/shared/collectedHeap.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "jvmtifiles/jvmti.h"
#include "jvmtifiles/jvmtiEnv.hpp"
#include "memory/allocation.hpp"
--- a/src/hotspot/share/runtime/arguments.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/arguments.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -29,11 +29,9 @@
#include "classfile/moduleEntry.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
+#include "gc/shared/collectorPolicy.hpp"
#include "gc/shared/gcArguments.hpp"
#include "gc/shared/gcConfig.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
-#include "gc/shared/referenceProcessor.hpp"
-#include "gc/shared/taskqueue.hpp"
#include "logging/log.hpp"
#include "logging/logConfiguration.hpp"
#include "logging/logStream.hpp"
@@ -98,6 +96,8 @@
intx Arguments::_Tier3InvokeNotifyFreqLog = Tier3InvokeNotifyFreqLog;
intx Arguments::_Tier4InvocationThreshold = Tier4InvocationThreshold;
+bool Arguments::_enable_preview = false;
+
char* Arguments::SharedArchivePath = NULL;
AgentLibraryList Arguments::_libraryList;
@@ -1446,35 +1446,23 @@
}
#if INCLUDE_CDS
+const char* unsupported_properties[] = { "jdk.module.limitmods",
+ "jdk.module.upgrade.path",
+ "jdk.module.patch.0" };
+const char* unsupported_options[] = { "--limit-modules",
+ "--upgrade-module-path",
+ "--patch-module"
+ };
void Arguments::check_unsupported_dumping_properties() {
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
- const char* unsupported_properties[] = { "jdk.module.main",
- "jdk.module.limitmods",
- "jdk.module.path",
- "jdk.module.upgrade.path",
- "jdk.module.patch.0" };
- const char* unsupported_options[] = { "-m", // cannot use at dump time
- "--limit-modules", // ignored at dump time
- "--module-path", // ignored at dump time
- "--upgrade-module-path", // ignored at dump time
- "--patch-module" // ignored at dump time
- };
assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
- // If a vm option is found in the unsupported_options array with index less than the info_idx,
- // vm will exit with an error message. Otherwise, it will print an informational message if
- // -Xlog:cds is enabled.
- uint info_idx = 1;
+ // If a vm option is found in the unsupported_options array, vm will exit with an error message.
SystemProperty* sp = system_properties();
while (sp != NULL) {
for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) {
if (strcmp(sp->key(), unsupported_properties[i]) == 0) {
- if (i < info_idx) {
- vm_exit_during_initialization(
- "Cannot use the following option when dumping the shared archive", unsupported_options[i]);
- } else {
- log_info(cds)("Info: the %s option is ignored when dumping the shared archive",
- unsupported_options[i]);
- }
+ vm_exit_during_initialization(
+ "Cannot use the following option when dumping the shared archive", unsupported_options[i]);
}
}
sp = sp->next();
@@ -1485,6 +1473,20 @@
vm_exit_during_initialization("Dumping the shared archive is not supported with an exploded module build");
}
}
+
+bool Arguments::check_unsupported_cds_runtime_properties() {
+ assert(UseSharedSpaces, "this function is only used with -Xshare:{on,auto}");
+ assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
+ for (uint i = 0; i < ARRAY_SIZE(unsupported_properties); i++) {
+ if (get_property(unsupported_properties[i]) != NULL) {
+ if (RequireSharedSpaces) {
+ warning("CDS is disabled when the %s option is specified.", unsupported_options[i]);
+ }
+ return true;
+ }
+ }
+ return false;
+}
#endif
//===========================================================================================================
@@ -2190,41 +2192,6 @@
status = false;
}
- if (FullGCALot && FLAG_IS_DEFAULT(MarkSweepAlwaysCompactCount)) {
- MarkSweepAlwaysCompactCount = 1; // Move objects every gc.
- }
-
- if (!(UseParallelGC || UseParallelOldGC) && FLAG_IS_DEFAULT(ScavengeBeforeFullGC)) {
- FLAG_SET_DEFAULT(ScavengeBeforeFullGC, false);
- }
-
- if (GCTimeLimit == 100) {
- // Turn off gc-overhead-limit-exceeded checks
- FLAG_SET_DEFAULT(UseGCOverheadLimit, false);
- }
-
- // CMS space iteration, which FLSVerifyAllHeapreferences entails,
- // insists that we hold the requisite locks so that the iteration is
- // MT-safe. For the verification at start-up and shut-down, we don't
- // yet have a good way of acquiring and releasing these locks,
- // which are not visible at the CollectedHeap level. We want to
- // be able to acquire these locks and then do the iteration rather
- // than just disable the lock verification. This will be fixed under
- // bug 4788986.
- if (UseConcMarkSweepGC && FLSVerifyAllHeapReferences) {
- if (VerifyDuringStartup) {
- warning("Heap verification at start-up disabled "
- "(due to current incompatibility with FLSVerifyAllHeapReferences)");
- VerifyDuringStartup = false; // Disable verification at start-up
- }
-
- if (VerifyBeforeExit) {
- warning("Heap verification at shutdown disabled "
- "(due to current incompatibility with FLSVerifyAllHeapReferences)");
- VerifyBeforeExit = false; // Disable verification at shutdown
- }
- }
-
if (PrintNMTStatistics) {
#if INCLUDE_NMT
if (MemTracker::tracking_level() == NMT_off) {
@@ -2776,6 +2743,9 @@
}
}
#endif // !INCLUDE_JVMTI
+ // --enable_preview
+ } else if (match_option(option, "--enable-preview")) {
+ set_enable_preview();
// -Xnoclassgc
} else if (match_option(option, "-Xnoclassgc")) {
if (FLAG_SET_CMDLINE(bool, ClassUnloading, false) != Flag::SUCCESS) {
@@ -3410,6 +3380,9 @@
if (UseSharedSpaces && patch_mod_javabase) {
no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched.");
}
+ if (UseSharedSpaces && !DumpSharedSpaces && check_unsupported_cds_runtime_properties()) {
+ FLAG_SET_DEFAULT(UseSharedSpaces, false);
+ }
#endif
#ifndef CAN_SHOW_REGISTERS_ON_ASSERT
--- a/src/hotspot/share/runtime/arguments.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/arguments.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -358,6 +358,9 @@
static void set_xdebug_mode(bool arg) { _xdebug_mode = arg; }
static bool xdebug_mode() { return _xdebug_mode; }
+ // preview features
+ static bool _enable_preview;
+
// Used to save default settings
static bool _AlwaysCompileLoopMethods;
static bool _UseOnStackReplacement;
@@ -691,12 +694,17 @@
static Mode mode() { return _mode; }
static bool is_interpreter_only() { return mode() == _int; }
+ // preview features
+ static void set_enable_preview() { _enable_preview = true; }
+ static bool enable_preview() { return _enable_preview; }
// Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid.
static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen);
static void check_unsupported_dumping_properties() NOT_CDS_RETURN;
+ static bool check_unsupported_cds_runtime_properties() NOT_CDS_RETURN0;
+
static bool atojulong(const char *s, julong* result);
};
--- a/src/hotspot/share/runtime/biasedLocking.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/biasedLocking.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -616,7 +616,7 @@
// with it.
markOop biased_value = mark;
markOop res_mark = obj->cas_set_mark(prototype_header, mark);
- assert(!(*(obj->mark_addr()))->has_bias_pattern(), "even if we raced, should still be revoked");
+ assert(!obj->mark()->has_bias_pattern(), "even if we raced, should still be revoked");
return BIAS_REVOKED;
} else if (prototype_header->bias_epoch() != mark->bias_epoch()) {
// The epoch of this biasing has expired indicating that the
--- a/src/hotspot/share/runtime/commandLineFlagConstraintList.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/commandLineFlagConstraintList.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,17 +25,13 @@
#include "precompiled.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
-#include "gc/shared/referenceProcessor.hpp"
+#include "gc/shared/commandLineFlagConstraintsGC.hpp"
#include "runtime/arguments.hpp"
#include "runtime/commandLineFlagConstraintList.hpp"
#include "runtime/commandLineFlagConstraintsCompiler.hpp"
-#include "runtime/commandLineFlagConstraintsGC.hpp"
#include "runtime/commandLineFlagConstraintsRuntime.hpp"
#include "runtime/os.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1_globals.hpp"
-#endif
#ifdef COMPILER1
#include "c1/c1_globals.hpp"
#endif
@@ -280,20 +276,20 @@
void CommandLineFlagConstraintList::init(void) {
_constraints = new (ResourceObj::C_HEAP, mtArguments) GrowableArray<CommandLineFlagConstraint*>(INITIAL_CONSTRAINTS_SIZE, true);
- emit_constraint_no(NULL RUNTIME_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PRODUCT_FLAG,
- EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
- EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_PD_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
- EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
- EMIT_CONSTRAINT_MANAGEABLE_FLAG,
- EMIT_CONSTRAINT_PRODUCT_RW_FLAG,
- EMIT_CONSTRAINT_LP64_PRODUCT_FLAG,
- IGNORE_RANGE,
- EMIT_CONSTRAINT_CHECK,
- IGNORE_WRITEABLE));
+ emit_constraint_no(NULL VM_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
+ EMIT_CONSTRAINT_PD_DIAGNOSTIC_FLAG,
+ EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
+ EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
+ EMIT_CONSTRAINT_MANAGEABLE_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_RW_FLAG,
+ EMIT_CONSTRAINT_LP64_PRODUCT_FLAG,
+ IGNORE_RANGE,
+ EMIT_CONSTRAINT_CHECK,
+ IGNORE_WRITEABLE));
EMIT_CONSTRAINTS_FOR_GLOBALS_EXT
@@ -333,22 +329,6 @@
EMIT_CONSTRAINT_CHECK,
IGNORE_WRITEABLE));
#endif // COMPILER2
-
-#if INCLUDE_ALL_GCS
- emit_constraint_no(NULL G1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
- EMIT_CONSTRAINT_PRODUCT_FLAG,
- EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
- EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_PD_DIAGNOSTIC_FLAG,
- EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
- EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
- EMIT_CONSTRAINT_MANAGEABLE_FLAG,
- EMIT_CONSTRAINT_PRODUCT_RW_FLAG,
- IGNORE_RANGE,
- EMIT_CONSTRAINT_CHECK,
- IGNORE_WRITEABLE));
-#endif // INCLUDE_ALL_GCS
}
CommandLineFlagConstraint* CommandLineFlagConstraintList::find(const char* name) {
--- a/src/hotspot/share/runtime/commandLineFlagConstraintsGC.cpp Tue Apr 17 08:54:17 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,810 +0,0 @@
-/*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
- * 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/shared/collectedHeap.hpp"
-#include "gc/shared/collectorPolicy.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
-#include "gc/shared/threadLocalAllocBuffer.hpp"
-#include "runtime/arguments.hpp"
-#include "runtime/commandLineFlagConstraintsGC.hpp"
-#include "runtime/commandLineFlagRangeList.hpp"
-#include "runtime/globals.hpp"
-#include "runtime/globals_extension.hpp"
-#include "runtime/thread.inline.hpp"
-#include "utilities/align.hpp"
-#include "utilities/defaultStream.hpp"
-
-#if INCLUDE_ALL_GCS
-#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
-#include "gc/g1/g1_globals.hpp"
-#include "gc/g1/heapRegionBounds.inline.hpp"
-#include "gc/shared/plab.hpp"
-#endif // INCLUDE_ALL_GCS
-#ifdef COMPILER1
-#include "c1/c1_globals.hpp"
-#endif // COMPILER1
-#ifdef COMPILER2
-#include "opto/c2_globals.hpp"
-#endif // COMPILER2
-
-// Some flags that have default values that indicate that the
-// JVM should automatically determine an appropriate value
-// for that flag. In those cases it is only appropriate for the
-// constraint checking to be done if the user has specified the
-// value(s) of the flag(s) on the command line. In the constraint
-// checking functions, FLAG_IS_CMDLINE() is used to check if
-// the flag has been set by the user and so should be checked.
-
-#if INCLUDE_ALL_GCS
-static Flag::Error ParallelGCThreadsAndCMSWorkQueueDrainThreshold(uint threads, uintx threshold, bool verbose) {
- // CMSWorkQueueDrainThreshold is verified to be less than max_juint
- if (UseConcMarkSweepGC && (threads > (uint)(max_jint / (uint)threshold))) {
- CommandLineError::print(verbose,
- "ParallelGCThreads (" UINT32_FORMAT ") or CMSWorkQueueDrainThreshold ("
- UINTX_FORMAT ") is too large\n",
- threads, threshold);
- return Flag::VIOLATES_CONSTRAINT;
- }
- return Flag::SUCCESS;
-}
-#endif
-
-// As ParallelGCThreads differs among GC modes, we need constraint function.
-Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) {
- Flag::Error status = Flag::SUCCESS;
-
-#if INCLUDE_ALL_GCS
- // Parallel GC passes ParallelGCThreads when creating GrowableArray as 'int' type parameter.
- // So can't exceed with "max_jint"
- if (UseParallelGC && (value > (uint)max_jint)) {
- CommandLineError::print(verbose,
- "ParallelGCThreads (" UINT32_FORMAT ") must be "
- "less than or equal to " UINT32_FORMAT " for Parallel GC\n",
- value, max_jint);
- return Flag::VIOLATES_CONSTRAINT;
- }
- // To avoid overflow at ParScanClosure::do_oop_work.
- if (UseConcMarkSweepGC && (value > (max_jint / 10))) {
- CommandLineError::print(verbose,
- "ParallelGCThreads (" UINT32_FORMAT ") must be "
- "less than or equal to " UINT32_FORMAT " for CMS GC\n",
- value, (max_jint / 10));
- return Flag::VIOLATES_CONSTRAINT;
- }
- status = ParallelGCThreadsAndCMSWorkQueueDrainThreshold(value, CMSWorkQueueDrainThreshold, verbose);
-#endif
- return status;
-}
-
-// As ConcGCThreads should be smaller than ParallelGCThreads,
-// we need constraint function.
-Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) {
-#if INCLUDE_ALL_GCS
- // CMS and G1 GCs use ConcGCThreads.
- if ((UseConcMarkSweepGC || UseG1GC) && (value > ParallelGCThreads)) {
- CommandLineError::print(verbose,
- "ConcGCThreads (" UINT32_FORMAT ") must be "
- "less than or equal to ParallelGCThreads (" UINT32_FORMAT ")\n",
- value, ParallelGCThreads);
- return Flag::VIOLATES_CONSTRAINT;
- }
-#endif
- return Flag::SUCCESS;
-}
-
-static Flag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value < PLAB::min_size())) {
- CommandLineError::print(verbose,
- "%s (" SIZE_FORMAT ") must be "
- "greater than or equal to ergonomic PLAB minimum size (" SIZE_FORMAT ")\n",
- name, value, PLAB::min_size());
- return Flag::VIOLATES_CONSTRAINT;
- }
-#endif // INCLUDE_ALL_GCS
- return Flag::SUCCESS;
-}
-
-static Flag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value > PLAB::max_size())) {
- CommandLineError::print(verbose,
- "%s (" SIZE_FORMAT ") must be "
- "less than or equal to ergonomic PLAB maximum size (" SIZE_FORMAT ")\n",
- name, value, PLAB::max_size());
- return Flag::VIOLATES_CONSTRAINT;
- }
-#endif // INCLUDE_ALL_GCS
- return Flag::SUCCESS;
-}
-
-static Flag::Error MinMaxPLABSizeBounds(const char* name, size_t value, bool verbose) {
- Flag::Error status = MinPLABSizeBounds(name, value, verbose);
-
- if (status == Flag::SUCCESS) {
- return MaxPLABSizeBounds(name, value, verbose);
- }
- return status;
-}
-
-Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose) {
- return MinMaxPLABSizeBounds("YoungPLABSize", value, verbose);
-}
-
-Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) {
- Flag::Error status = Flag::SUCCESS;
-
-#if INCLUDE_ALL_GCS
- if (UseConcMarkSweepGC) {
- if (value == 0) {
- CommandLineError::print(verbose,
- "OldPLABSize (" SIZE_FORMAT ") must be greater than 0",
- value);
- return Flag::VIOLATES_CONSTRAINT;
- }
- // For CMS, OldPLABSize is the number of free blocks of a given size that are used when
- // replenishing the local per-worker free list caches.
- // For more details, please refer to Arguments::set_cms_and_parnew_gc_flags().
- status = MaxPLABSizeBounds("OldPLABSize", value, verbose);
- } else {
- status = MinMaxPLABSizeBounds("OldPLABSize", value, verbose);
- }
-#endif
- return status;
-}
-
-Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose) {
- if (value > MaxHeapFreeRatio) {
- CommandLineError::print(verbose,
- "MinHeapFreeRatio (" UINTX_FORMAT ") must be "
- "less than or equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n",
- value, MaxHeapFreeRatio);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose) {
- if (value < MinHeapFreeRatio) {
- CommandLineError::print(verbose,
- "MaxHeapFreeRatio (" UINTX_FORMAT ") must be "
- "greater than or equal to MinHeapFreeRatio (" UINTX_FORMAT ")\n",
- value, MinHeapFreeRatio);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-static Flag::Error CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(size_t maxHeap, intx softRef, bool verbose) {
- if ((softRef > 0) && ((maxHeap / M) > (max_uintx / softRef))) {
- CommandLineError::print(verbose,
- "Desired lifetime of SoftReferences cannot be expressed correctly. "
- "MaxHeapSize (" SIZE_FORMAT ") or SoftRefLRUPolicyMSPerMB "
- "(" INTX_FORMAT ") is too large\n",
- maxHeap, softRef);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose) {
- return CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(MaxHeapSize, value, verbose);
-}
-
-Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) {
- if (value > MaxMetaspaceFreeRatio) {
- CommandLineError::print(verbose,
- "MinMetaspaceFreeRatio (" UINTX_FORMAT ") must be "
- "less than or equal to MaxMetaspaceFreeRatio (" UINTX_FORMAT ")\n",
- value, MaxMetaspaceFreeRatio);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose) {
- if (value < MinMetaspaceFreeRatio) {
- CommandLineError::print(verbose,
- "MaxMetaspaceFreeRatio (" UINTX_FORMAT ") must be "
- "greater than or equal to MinMetaspaceFreeRatio (" UINTX_FORMAT ")\n",
- value, MinMetaspaceFreeRatio);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
- // InitialTenuringThreshold is only used for ParallelGC.
- if (UseParallelGC && (value > MaxTenuringThreshold)) {
- CommandLineError::print(verbose,
- "InitialTenuringThreshold (" UINTX_FORMAT ") must be "
- "less than or equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n",
- value, MaxTenuringThreshold);
- return Flag::VIOLATES_CONSTRAINT;
- }
-#endif
- return Flag::SUCCESS;
-}
-
-Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
- // As only ParallelGC uses InitialTenuringThreshold,
- // we don't need to compare InitialTenuringThreshold with MaxTenuringThreshold.
- if (UseParallelGC && (value < InitialTenuringThreshold)) {
- CommandLineError::print(verbose,
- "MaxTenuringThreshold (" UINTX_FORMAT ") must be "
- "greater than or equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n",
- value, InitialTenuringThreshold);
- return Flag::VIOLATES_CONSTRAINT;
- }
-#endif
-
- // MaxTenuringThreshold=0 means NeverTenure=false && AlwaysTenure=true
- if ((value == 0) && (NeverTenure || !AlwaysTenure)) {
- CommandLineError::print(verbose,
- "MaxTenuringThreshold (0) should match to NeverTenure=false "
- "&& AlwaysTenure=true. But we have NeverTenure=%s "
- "AlwaysTenure=%s\n",
- NeverTenure ? "true" : "false",
- AlwaysTenure ? "true" : "false");
- return Flag::VIOLATES_CONSTRAINT;
- }
- return Flag::SUCCESS;
-}
-
-#if INCLUDE_ALL_GCS
-Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose) {
- if (!UseG1GC) return Flag::SUCCESS;
-
- // Default value of G1RSetRegionEntries=0 means will be set ergonomically.
- // Minimum value is 1.
- if (FLAG_IS_CMDLINE(G1RSetRegionEntries) && (value < 1)) {
- CommandLineError::print(verbose,
- "G1RSetRegionEntries (" INTX_FORMAT ") must be "
- "greater than or equal to 1\n",
- value);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose) {
- if (!UseG1GC) return Flag::SUCCESS;
-
- // Default value of G1RSetSparseRegionEntries=0 means will be set ergonomically.
- // Minimum value is 1.
- if (FLAG_IS_CMDLINE(G1RSetSparseRegionEntries) && (value < 1)) {
- CommandLineError::print(verbose,
- "G1RSetSparseRegionEntries (" INTX_FORMAT ") must be "
- "greater than or equal to 1\n",
- value);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose) {
- if (!UseG1GC) return Flag::SUCCESS;
-
- // Default value of G1HeapRegionSize=0 means will be set ergonomically.
- if (FLAG_IS_CMDLINE(G1HeapRegionSize) && (value < HeapRegionBounds::min_size())) {
- CommandLineError::print(verbose,
- "G1HeapRegionSize (" SIZE_FORMAT ") must be "
- "greater than or equal to ergonomic heap region minimum size\n",
- value);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose) {
- if (!UseG1GC) return Flag::SUCCESS;
-
- if (value > G1MaxNewSizePercent) {
- CommandLineError::print(verbose,
- "G1NewSizePercent (" UINTX_FORMAT ") must be "
- "less than or equal to G1MaxNewSizePercent (" UINTX_FORMAT ")\n",
- value, G1MaxNewSizePercent);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose) {
- if (!UseG1GC) return Flag::SUCCESS;
-
- if (value < G1NewSizePercent) {
- CommandLineError::print(verbose,
- "G1MaxNewSizePercent (" UINTX_FORMAT ") must be "
- "greater than or equal to G1NewSizePercent (" UINTX_FORMAT ")\n",
- value, G1NewSizePercent);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-#endif // INCLUDE_ALL_GCS
-
-Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if (UseConcMarkSweepGC && (value > ((uintx)max_jint / (uintx)ParallelGCThreads))) {
- CommandLineError::print(verbose,
- "ParGCStridesPerThread (" UINTX_FORMAT ") must be "
- "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n",
- value, ((uintx)max_jint / (uintx)ParallelGCThreads));
- return Flag::VIOLATES_CONSTRAINT;
- }
-#endif
- return Flag::SUCCESS;
-}
-
-Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if (UseConcMarkSweepGC) {
- // ParGCCardsPerStrideChunk should be compared with card table size.
- size_t heap_size = Universe::heap()->reserved_region().word_size();
- CardTableRS* ct = GenCollectedHeap::heap()->rem_set();
- size_t card_table_size = ct->cards_required(heap_size) - 1; // Valid card table size
-
- if ((size_t)value > card_table_size) {
- CommandLineError::print(verbose,
- "ParGCCardsPerStrideChunk (" INTX_FORMAT ") is too large for the heap size and "
- "must be less than or equal to card table size (" SIZE_FORMAT ")\n",
- value, card_table_size);
- return Flag::VIOLATES_CONSTRAINT;
- }
-
- // ParGCCardsPerStrideChunk is used with n_strides(ParallelGCThreads*ParGCStridesPerThread)
- // from CardTableRS::process_stride(). Note that ParGCStridesPerThread is already checked
- // not to make an overflow with ParallelGCThreads from its constraint function.
- uintx n_strides = ParallelGCThreads * ParGCStridesPerThread;
- uintx ergo_max = max_uintx / n_strides;
- if ((uintx)value > ergo_max) {
- CommandLineError::print(verbose,
- "ParGCCardsPerStrideChunk (" INTX_FORMAT ") must be "
- "less than or equal to ergonomic maximum (" UINTX_FORMAT ")\n",
- value, ergo_max);
- return Flag::VIOLATES_CONSTRAINT;
- }
- }
-#endif
- return Flag::SUCCESS;
-}
-
-Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose) {
- Flag::Error status = Flag::SUCCESS;
-
-#if INCLUDE_ALL_GCS
- if (UseConcMarkSweepGC) {
- if (value > CMSOldPLABMax) {
- CommandLineError::print(verbose,
- "CMSOldPLABMin (" SIZE_FORMAT ") must be "
- "less than or equal to CMSOldPLABMax (" SIZE_FORMAT ")\n",
- value, CMSOldPLABMax);
- return Flag::VIOLATES_CONSTRAINT;
- }
- status = MaxPLABSizeBounds("CMSOldPLABMin", value, verbose);
- }
-#endif
- return status;
-}
-
-Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose) {
- Flag::Error status = Flag::SUCCESS;
-
-#if INCLUDE_ALL_GCS
- if (UseConcMarkSweepGC) {
- status = MaxPLABSizeBounds("CMSOldPLABMax", value, verbose);
- }
-#endif
- return status;
-}
-
-Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose) {
- if (value > MarkStackSizeMax) {
- CommandLineError::print(verbose,
- "MarkStackSize (" SIZE_FORMAT ") must be "
- "less than or equal to MarkStackSizeMax (" SIZE_FORMAT ")\n",
- value, MarkStackSizeMax);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-static Flag::Error CMSReservedAreaConstraintFunc(const char* name, size_t value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if (UseConcMarkSweepGC) {
- ConcurrentMarkSweepGeneration* cms = (ConcurrentMarkSweepGeneration*)GenCollectedHeap::heap()->old_gen();
- const size_t ergo_max = cms->cmsSpace()->max_flag_size_for_task_size();
- if (value > ergo_max) {
- CommandLineError::print(verbose,
- "%s (" SIZE_FORMAT ") must be "
- "less than or equal to ergonomic maximum (" SIZE_FORMAT ") "
- "which is based on the maximum size of the old generation of the Java heap\n",
- name, value, ergo_max);
- return Flag::VIOLATES_CONSTRAINT;
- }
- }
-#endif
-
- return Flag::SUCCESS;
-}
-
-Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) {
- Flag::Error status = CMSReservedAreaConstraintFunc("CMSRescanMultiple", value, verbose);
-
-#if INCLUDE_ALL_GCS
- if (status == Flag::SUCCESS && UseConcMarkSweepGC) {
- // CMSParRemarkTask::do_dirty_card_rescan_tasks requires CompactibleFreeListSpace::rescan_task_size()
- // to be aligned to CardTable::card_size * BitsPerWord.
- // Note that rescan_task_size() will be aligned if CMSRescanMultiple is a multiple of 'HeapWordSize'
- // because rescan_task_size() is CardTable::card_size / HeapWordSize * BitsPerWord.
- if (value % HeapWordSize != 0) {
- CommandLineError::print(verbose,
- "CMSRescanMultiple (" SIZE_FORMAT ") must be "
- "a multiple of " SIZE_FORMAT "\n",
- value, HeapWordSize);
- status = Flag::VIOLATES_CONSTRAINT;
- }
- }
-#endif
-
- return status;
-}
-
-Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose) {
- return CMSReservedAreaConstraintFunc("CMSConcMarkMultiple", value, verbose);
-}
-
-Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if (UseConcMarkSweepGC && (value <= CMSPrecleanNumerator)) {
- CommandLineError::print(verbose,
- "CMSPrecleanDenominator (" UINTX_FORMAT ") must be "
- "strickly greater than CMSPrecleanNumerator (" UINTX_FORMAT ")\n",
- value, CMSPrecleanNumerator);
- return Flag::VIOLATES_CONSTRAINT;
- }
-#endif
- return Flag::SUCCESS;
-}
-
-Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if (UseConcMarkSweepGC && (value >= CMSPrecleanDenominator)) {
- CommandLineError::print(verbose,
- "CMSPrecleanNumerator (" UINTX_FORMAT ") must be "
- "less than CMSPrecleanDenominator (" UINTX_FORMAT ")\n",
- value, CMSPrecleanDenominator);
- return Flag::VIOLATES_CONSTRAINT;
- }
-#endif
- return Flag::SUCCESS;
-}
-
-Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if (UseConcMarkSweepGC) {
- size_t max_capacity = GenCollectedHeap::heap()->young_gen()->max_capacity();
- if (value > max_uintx - max_capacity) {
- CommandLineError::print(verbose,
- "CMSSamplingGrain (" UINTX_FORMAT ") must be "
- "less than or equal to ergonomic maximum (" SIZE_FORMAT ")\n",
- value, max_uintx - max_capacity);
- return Flag::VIOLATES_CONSTRAINT;
- }
- }
-#endif
- return Flag::SUCCESS;
-}
-
-Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if (UseConcMarkSweepGC) {
- return ParallelGCThreadsAndCMSWorkQueueDrainThreshold(ParallelGCThreads, value, verbose);
- }
-#endif
- return Flag::SUCCESS;
-}
-
-Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose) {
-#if INCLUDE_ALL_GCS
- // Skip for current default value.
- if (UseConcMarkSweepGC && FLAG_IS_CMDLINE(CMSBitMapYieldQuantum)) {
- // CMSBitMapYieldQuantum should be compared with mark bitmap size.
- ConcurrentMarkSweepGeneration* cms = (ConcurrentMarkSweepGeneration*)GenCollectedHeap::heap()->old_gen();
- size_t bitmap_size = cms->collector()->markBitMap()->sizeInWords();
-
- if (value > bitmap_size) {
- CommandLineError::print(verbose,
- "CMSBitMapYieldQuantum (" SIZE_FORMAT ") must "
- "be less than or equal to bitmap size (" SIZE_FORMAT ") "
- "whose size corresponds to the size of old generation of the Java heap\n",
- value, bitmap_size);
- return Flag::VIOLATES_CONSTRAINT;
- }
- }
-#endif
- return Flag::SUCCESS;
-}
-
-Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if (UseG1GC && FLAG_IS_CMDLINE(MaxGCPauseMillis) && (value >= GCPauseIntervalMillis)) {
- CommandLineError::print(verbose,
- "MaxGCPauseMillis (" UINTX_FORMAT ") must be "
- "less than GCPauseIntervalMillis (" UINTX_FORMAT ")\n",
- value, GCPauseIntervalMillis);
- return Flag::VIOLATES_CONSTRAINT;
- }
-#endif
-
- return Flag::SUCCESS;
-}
-
-Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- if (FLAG_IS_CMDLINE(GCPauseIntervalMillis)) {
- if (value < 1) {
- CommandLineError::print(verbose,
- "GCPauseIntervalMillis (" UINTX_FORMAT ") must be "
- "greater than or equal to 1\n",
- value);
- return Flag::VIOLATES_CONSTRAINT;
- }
-
- if (FLAG_IS_DEFAULT(MaxGCPauseMillis)) {
- CommandLineError::print(verbose,
- "GCPauseIntervalMillis cannot be set "
- "without setting MaxGCPauseMillis\n");
- return Flag::VIOLATES_CONSTRAINT;
- }
-
- if (value <= MaxGCPauseMillis) {
- CommandLineError::print(verbose,
- "GCPauseIntervalMillis (" UINTX_FORMAT ") must be "
- "greater than MaxGCPauseMillis (" UINTX_FORMAT ")\n",
- value, MaxGCPauseMillis);
- return Flag::VIOLATES_CONSTRAINT;
- }
- }
- }
-#endif
- return Flag::SUCCESS;
-}
-
-Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose) {
- size_t aligned_max = align_down(max_uintx/2, Metaspace::reserve_alignment_words());
- if (value > aligned_max) {
- CommandLineError::print(verbose,
- "InitialBootClassLoaderMetaspaceSize (" SIZE_FORMAT ") must be "
- "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n",
- value, aligned_max);
- return Flag::VIOLATES_CONSTRAINT;
- }
- return Flag::SUCCESS;
-}
-
-// To avoid an overflow by 'align_up(value, alignment)'.
-static Flag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) {
- size_t aligned_max = ((max_uintx - alignment) & ~(alignment-1));
- if (value > aligned_max) {
- CommandLineError::print(verbose,
- "%s (" SIZE_FORMAT ") must be "
- "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n",
- name, value, aligned_max);
- return Flag::VIOLATES_CONSTRAINT;
- }
- return Flag::SUCCESS;
-}
-
-static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) {
- // For G1 GC, we don't know until G1CollectorPolicy is created.
- size_t heap_alignment;
-
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- heap_alignment = HeapRegionBounds::max_size();
- } else
-#endif
- {
- heap_alignment = CollectorPolicy::compute_heap_alignment();
- }
-
- return MaxSizeForAlignment(name, value, heap_alignment, verbose);
-}
-
-Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) {
- return MaxSizeForHeapAlignment("InitialHeapSize", value, verbose);
-}
-
-Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) {
- Flag::Error status = MaxSizeForHeapAlignment("MaxHeapSize", value, verbose);
-
- if (status == Flag::SUCCESS) {
- status = CheckMaxHeapSizeAndSoftRefLRUPolicyMSPerMB(value, SoftRefLRUPolicyMSPerMB, verbose);
- }
- return status;
-}
-
-Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) {
- // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value.
- // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx.
- if (UseCompressedOops && FLAG_IS_ERGO(MaxHeapSize) && (value > (max_uintx - MaxHeapSize))) {
- CommandLineError::print(verbose,
- "HeapBaseMinAddress (" SIZE_FORMAT ") or MaxHeapSize (" SIZE_FORMAT ") is too large. "
- "Sum of them must be less than or equal to maximum of size_t (" SIZE_FORMAT ")\n",
- value, MaxHeapSize, max_uintx);
- return Flag::VIOLATES_CONSTRAINT;
- }
-
- return MaxSizeForHeapAlignment("HeapBaseMinAddress", value, verbose);
-}
-
-Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) {
-#ifdef _LP64
-#if INCLUDE_ALL_GCS
- // Overflow would happen for uint type variable of YoungGenSizer::_min_desired_young_length
- // when the value to be assigned exceeds uint range.
- // i.e. result of '(uint)(NewSize / region size(1~32MB))'
- // So maximum of NewSize should be 'max_juint * 1M'
- if (UseG1GC && (value > (max_juint * 1 * M))) {
- CommandLineError::print(verbose,
- "NewSize (" SIZE_FORMAT ") must be less than ergonomic maximum value\n",
- value);
- return Flag::VIOLATES_CONSTRAINT;
- }
-#endif // INCLUDE_ALL_GCS
-#endif // _LP64
- return Flag::SUCCESS;
-}
-
-Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose) {
- // At least, alignment reserve area is needed.
- if (value < ThreadLocalAllocBuffer::alignment_reserve_in_bytes()) {
- CommandLineError::print(verbose,
- "MinTLABSize (" SIZE_FORMAT ") must be "
- "greater than or equal to reserved area in TLAB (" SIZE_FORMAT ")\n",
- value, ThreadLocalAllocBuffer::alignment_reserve_in_bytes());
- return Flag::VIOLATES_CONSTRAINT;
- }
- if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) {
- CommandLineError::print(verbose,
- "MinTLABSize (" SIZE_FORMAT ") must be "
- "less than or equal to ergonomic TLAB maximum (" SIZE_FORMAT ")\n",
- value, ThreadLocalAllocBuffer::max_size() * HeapWordSize);
- return Flag::VIOLATES_CONSTRAINT;
- }
- return Flag::SUCCESS;
-}
-
-Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) {
- // Skip for default value of zero which means set ergonomically.
- if (FLAG_IS_CMDLINE(TLABSize)) {
- if (value < MinTLABSize) {
- CommandLineError::print(verbose,
- "TLABSize (" SIZE_FORMAT ") must be "
- "greater than or equal to MinTLABSize (" SIZE_FORMAT ")\n",
- value, MinTLABSize);
- return Flag::VIOLATES_CONSTRAINT;
- }
- if (value > (ThreadLocalAllocBuffer::max_size() * HeapWordSize)) {
- CommandLineError::print(verbose,
- "TLABSize (" SIZE_FORMAT ") must be "
- "less than or equal to ergonomic TLAB maximum size (" SIZE_FORMAT ")\n",
- value, (ThreadLocalAllocBuffer::max_size() * HeapWordSize));
- return Flag::VIOLATES_CONSTRAINT;
- }
- }
- return Flag::SUCCESS;
-}
-
-// We will protect overflow from ThreadLocalAllocBuffer::record_slow_allocation(),
-// so AfterMemoryInit type is enough to check.
-Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) {
- if (UseTLAB) {
- size_t refill_waste_limit = Thread::current()->tlab().refill_waste_limit();
-
- // Compare with 'max_uintx' as ThreadLocalAllocBuffer::_refill_waste_limit is 'size_t'.
- if (refill_waste_limit > (max_uintx - value)) {
- CommandLineError::print(verbose,
- "TLABWasteIncrement (" UINTX_FORMAT ") must be "
- "less than or equal to ergonomic TLAB waste increment maximum size(" SIZE_FORMAT ")\n",
- value, (max_uintx - refill_waste_limit));
- return Flag::VIOLATES_CONSTRAINT;
- }
- }
- return Flag::SUCCESS;
-}
-
-Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) {
- if (FLAG_IS_CMDLINE(SurvivorRatio) &&
- (value > (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()))) {
- CommandLineError::print(verbose,
- "SurvivorRatio (" UINTX_FORMAT ") must be "
- "less than or equal to ergonomic SurvivorRatio maximum (" SIZE_FORMAT ")\n",
- value,
- (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()));
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose) {
- if (value > MaxMetaspaceSize) {
- CommandLineError::print(verbose,
- "MetaspaceSize (" SIZE_FORMAT ") must be "
- "less than or equal to MaxMetaspaceSize (" SIZE_FORMAT ")\n",
- value, MaxMetaspaceSize);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) {
- if (value < MetaspaceSize) {
- CommandLineError::print(verbose,
- "MaxMetaspaceSize (" SIZE_FORMAT ") must be "
- "greater than or equal to MetaspaceSize (" SIZE_FORMAT ")\n",
- value, MaxMetaspaceSize);
- return Flag::VIOLATES_CONSTRAINT;
- } else {
- return Flag::SUCCESS;
- }
-}
-
-Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) {
- if (value != 0) {
- if (!is_power_of_2(value)) {
- CommandLineError::print(verbose,
- "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be "
- "power of 2\n",
- value);
- return Flag::VIOLATES_CONSTRAINT;
- }
- if (value < ObjectAlignmentInBytes) {
- CommandLineError::print(verbose,
- "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be "
- "greater than or equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n",
- value, ObjectAlignmentInBytes);
- return Flag::VIOLATES_CONSTRAINT;
- }
- }
- return Flag::SUCCESS;
-}
--- a/src/hotspot/share/runtime/commandLineFlagConstraintsGC.hpp Tue Apr 17 08:54:17 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * 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
- * 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_RUNTIME_COMMANDLINEFLAGCONSTRAINTSGC_HPP
-#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSGC_HPP
-
-#include "runtime/globals.hpp"
-#include "utilities/globalDefinitions.hpp"
-
-/*
- * Here we have GC arguments constraints functions, which are called automatically
- * whenever flag's value changes. If the constraint fails the function should return
- * an appropriate error value.
- */
-
-Flag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose);
-Flag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose);
-Flag::Error YoungPLABSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error MinHeapFreeRatioConstraintFunc(uintx value, bool verbose);
-Flag::Error MaxHeapFreeRatioConstraintFunc(uintx value, bool verbose);
-Flag::Error SoftRefLRUPolicyMSPerMBConstraintFunc(intx value, bool verbose);
-Flag::Error MinMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose);
-Flag::Error MaxMetaspaceFreeRatioConstraintFunc(uintx value, bool verbose);
-Flag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose);
-Flag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose);
-
-#if INCLUDE_ALL_GCS
-Flag::Error G1RSetRegionEntriesConstraintFunc(intx value, bool verbose);
-Flag::Error G1RSetSparseRegionEntriesConstraintFunc(intx value, bool verbose);
-Flag::Error G1HeapRegionSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error G1NewSizePercentConstraintFunc(uintx value, bool verbose);
-Flag::Error G1MaxNewSizePercentConstraintFunc(uintx value, bool verbose);
-#endif // INCLUDE_ALL_GCS
-
-Flag::Error ParGCStridesPerThreadConstraintFunc(uintx value, bool verbose);
-Flag::Error ParGCCardsPerStrideChunkConstraintFunc(intx value, bool verbose);
-Flag::Error CMSOldPLABMinConstraintFunc(size_t value, bool verbose);
-Flag::Error CMSOldPLABMaxConstraintFunc(size_t value, bool verbose);
-Flag::Error MarkStackSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose);
-Flag::Error CMSConcMarkMultipleConstraintFunc(size_t value, bool verbose);
-Flag::Error CMSPrecleanDenominatorConstraintFunc(uintx value, bool verbose);
-Flag::Error CMSPrecleanNumeratorConstraintFunc(uintx value, bool verbose);
-Flag::Error CMSSamplingGrainConstraintFunc(uintx value, bool verbose);
-Flag::Error CMSWorkQueueDrainThresholdConstraintFunc(uintx value, bool verbose);
-Flag::Error CMSBitMapYieldQuantumConstraintFunc(size_t value, bool verbose);
-Flag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose);
-Flag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose);
-Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose);
-Flag::Error NewSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose);
-Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose);
-Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose);
-Flag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose);
-
-#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSGC_HPP */
--- a/src/hotspot/share/runtime/commandLineFlagRangeList.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/commandLineFlagRangeList.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -335,20 +335,20 @@
_ranges = new (ResourceObj::C_HEAP, mtArguments) GrowableArray<CommandLineFlagRange*>(INITIAL_RANGES_SIZE, true);
- emit_range_no(NULL RUNTIME_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PD_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_PD_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_PD_DIAGNOSTIC_FLAG,
- EMIT_RANGE_EXPERIMENTAL_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_MANAGEABLE_FLAG,
- EMIT_RANGE_PRODUCT_RW_FLAG,
- EMIT_RANGE_LP64_PRODUCT_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE));
+ emit_range_no(NULL VM_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
+ EMIT_RANGE_PD_DEVELOPER_FLAG,
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_PD_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_PD_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_EXPERIMENTAL_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_MANAGEABLE_FLAG,
+ EMIT_RANGE_PRODUCT_RW_FLAG,
+ EMIT_RANGE_LP64_PRODUCT_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT,
+ IGNORE_WRITEABLE));
EMIT_RANGES_FOR_GLOBALS_EXT
@@ -401,22 +401,6 @@
IGNORE_CONSTRAINT,
IGNORE_WRITEABLE));
#endif // COMPILER2
-
-#if INCLUDE_ALL_GCS
- emit_range_no(NULL G1_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
- EMIT_RANGE_PD_DEVELOPER_FLAG,
- EMIT_RANGE_PRODUCT_FLAG,
- EMIT_RANGE_PD_PRODUCT_FLAG,
- EMIT_RANGE_DIAGNOSTIC_FLAG,
- EMIT_RANGE_PD_DIAGNOSTIC_FLAG,
- EMIT_RANGE_EXPERIMENTAL_FLAG,
- EMIT_RANGE_NOTPRODUCT_FLAG,
- EMIT_RANGE_MANAGEABLE_FLAG,
- EMIT_RANGE_PRODUCT_RW_FLAG,
- EMIT_RANGE_CHECK,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE));
-#endif // INCLUDE_ALL_GCS
}
CommandLineFlagRange* CommandLineFlagRangeList::find(const char* name) {
--- a/src/hotspot/share/runtime/commandLineFlagWriteableList.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/commandLineFlagWriteableList.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -23,14 +23,9 @@
*/
#include "precompiled.hpp"
+#include "gc/shared/plab.hpp"
#include "runtime/commandLineFlagWriteableList.hpp"
#include "runtime/os.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/cms/concurrentMarkSweepGeneration.inline.hpp"
-#include "gc/g1/g1_globals.hpp"
-#include "gc/g1/heapRegionBounds.inline.hpp"
-#include "gc/shared/plab.hpp"
-#endif // INCLUDE_ALL_GCS
#ifdef COMPILER1
#include "c1/c1_globals.hpp"
#endif // COMPILER1
@@ -122,20 +117,20 @@
_controls = new (ResourceObj::C_HEAP, mtArguments) GrowableArray<CommandLineFlagWriteable*>(INITIAL_WRITEABLES_SIZE, true);
- emit_writeable_no(NULL RUNTIME_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PD_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PRODUCT_FLAG,
- EMIT_WRITEABLE_PD_PRODUCT_FLAG,
- EMIT_WRITEABLE_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_PD_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_EXPERIMENTAL_FLAG,
- EMIT_WRITEABLE_NOTPRODUCT_FLAG,
- EMIT_WRITEABLE_MANAGEABLE_FLAG,
- EMIT_WRITEABLE_PRODUCT_RW_FLAG,
- EMIT_WRITEABLE_LP64_PRODUCT_FLAG,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- EMIT_WRITEABLE));
+ emit_writeable_no(NULL VM_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG,
+ EMIT_WRITEABLE_PD_DEVELOPER_FLAG,
+ EMIT_WRITEABLE_PRODUCT_FLAG,
+ EMIT_WRITEABLE_PD_PRODUCT_FLAG,
+ EMIT_WRITEABLE_DIAGNOSTIC_FLAG,
+ EMIT_WRITEABLE_PD_DIAGNOSTIC_FLAG,
+ EMIT_WRITEABLE_EXPERIMENTAL_FLAG,
+ EMIT_WRITEABLE_NOTPRODUCT_FLAG,
+ EMIT_WRITEABLE_MANAGEABLE_FLAG,
+ EMIT_WRITEABLE_PRODUCT_RW_FLAG,
+ EMIT_WRITEABLE_LP64_PRODUCT_FLAG,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT,
+ EMIT_WRITEABLE));
EMIT_WRITEABLES_FOR_GLOBALS_EXT
@@ -188,22 +183,6 @@
IGNORE_CONSTRAINT,
EMIT_WRITEABLE));
#endif // COMPILER2
-
-#if INCLUDE_ALL_GCS
- emit_writeable_no(NULL G1_FLAGS(EMIT_WRITEABLE_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PD_DEVELOPER_FLAG,
- EMIT_WRITEABLE_PRODUCT_FLAG,
- EMIT_WRITEABLE_PD_PRODUCT_FLAG,
- EMIT_WRITEABLE_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_PD_DIAGNOSTIC_FLAG,
- EMIT_WRITEABLE_EXPERIMENTAL_FLAG,
- EMIT_WRITEABLE_NOTPRODUCT_FLAG,
- EMIT_WRITEABLE_MANAGEABLE_FLAG,
- EMIT_WRITEABLE_PRODUCT_RW_FLAG,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- EMIT_WRITEABLE));
-#endif // INCLUDE_ALL_GCS
}
CommandLineFlagWriteable* CommandLineFlagWriteableList::find(const char* name) {
--- a/src/hotspot/share/runtime/globals.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/globals.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -39,9 +39,6 @@
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#include "utilities/stringUtils.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1_globals.hpp"
-#endif // INCLUDE_ALL_GCS
#ifdef COMPILER1
#include "c1/c1_globals.hpp"
#endif
@@ -52,20 +49,20 @@
#include "opto/c2_globals.hpp"
#endif
-RUNTIME_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
- MATERIALIZE_PD_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, \
- MATERIALIZE_PD_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, \
- MATERIALIZE_PD_DIAGNOSTIC_FLAG, \
- MATERIALIZE_EXPERIMENTAL_FLAG, \
- MATERIALIZE_NOTPRODUCT_FLAG, \
- MATERIALIZE_MANAGEABLE_FLAG, \
- MATERIALIZE_PRODUCT_RW_FLAG, \
- MATERIALIZE_LP64_PRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
+VM_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
+ MATERIALIZE_PD_DEVELOPER_FLAG, \
+ MATERIALIZE_PRODUCT_FLAG, \
+ MATERIALIZE_PD_PRODUCT_FLAG, \
+ MATERIALIZE_DIAGNOSTIC_FLAG, \
+ MATERIALIZE_PD_DIAGNOSTIC_FLAG, \
+ MATERIALIZE_EXPERIMENTAL_FLAG, \
+ MATERIALIZE_NOTPRODUCT_FLAG, \
+ MATERIALIZE_MANAGEABLE_FLAG, \
+ MATERIALIZE_PRODUCT_RW_FLAG, \
+ MATERIALIZE_LP64_PRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT, \
+ IGNORE_WRITEABLE)
RUNTIME_OS_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
MATERIALIZE_PD_DEVELOPER_FLAG, \
@@ -870,20 +867,21 @@
#define ARCH_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), (void*) &name, NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_ARCH | Flag::KIND_NOT_PRODUCT) },
static Flag flagTable[] = {
- RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \
- RUNTIME_PD_DEVELOP_FLAG_STRUCT, \
- RUNTIME_PRODUCT_FLAG_STRUCT, \
- RUNTIME_PD_PRODUCT_FLAG_STRUCT, \
- RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \
- RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \
- RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \
- RUNTIME_NOTPRODUCT_FLAG_STRUCT, \
- RUNTIME_MANAGEABLE_FLAG_STRUCT, \
- RUNTIME_PRODUCT_RW_FLAG_STRUCT, \
- RUNTIME_LP64_PRODUCT_FLAG_STRUCT, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
+ VM_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \
+ RUNTIME_PD_DEVELOP_FLAG_STRUCT, \
+ RUNTIME_PRODUCT_FLAG_STRUCT, \
+ RUNTIME_PD_PRODUCT_FLAG_STRUCT, \
+ RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \
+ RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \
+ RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \
+ RUNTIME_NOTPRODUCT_FLAG_STRUCT, \
+ RUNTIME_MANAGEABLE_FLAG_STRUCT, \
+ RUNTIME_PRODUCT_RW_FLAG_STRUCT, \
+ RUNTIME_LP64_PRODUCT_FLAG_STRUCT, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT, \
+ IGNORE_WRITEABLE)
+
RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \
RUNTIME_PD_DEVELOP_FLAG_STRUCT, \
RUNTIME_PRODUCT_FLAG_STRUCT, \
@@ -894,21 +892,6 @@
IGNORE_RANGE, \
IGNORE_CONSTRAINT, \
IGNORE_WRITEABLE)
-#if INCLUDE_ALL_GCS
- G1_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \
- RUNTIME_PD_DEVELOP_FLAG_STRUCT, \
- RUNTIME_PRODUCT_FLAG_STRUCT, \
- RUNTIME_PD_PRODUCT_FLAG_STRUCT, \
- RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \
- RUNTIME_PD_DIAGNOSTIC_FLAG_STRUCT, \
- RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \
- RUNTIME_NOTPRODUCT_FLAG_STRUCT, \
- RUNTIME_MANAGEABLE_FLAG_STRUCT, \
- RUNTIME_PRODUCT_RW_FLAG_STRUCT, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-#endif // INCLUDE_ALL_GCS
#if INCLUDE_JVMCI
JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_STRUCT, \
JVMCI_PD_DEVELOP_FLAG_STRUCT, \
--- a/src/hotspot/share/runtime/globals.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/globals.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,6 +25,7 @@
#ifndef SHARE_VM_RUNTIME_GLOBALS_HPP
#define SHARE_VM_RUNTIME_GLOBALS_HPP
+#include "gc/shared/gc_globals.hpp"
#include "utilities/align.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
@@ -1385,936 +1386,17 @@
develop(bool, TraceCompiledIC, false, \
"Trace changes of compiled IC") \
\
- /* gc */ \
- \
- product(bool, UseSerialGC, false, \
- "Use the Serial garbage collector") \
- \
- product(bool, UseG1GC, false, \
- "Use the Garbage-First garbage collector") \
- \
- product(bool, UseParallelGC, false, \
- "Use the Parallel Scavenge garbage collector") \
- \
- product(bool, UseParallelOldGC, false, \
- "Use the Parallel Old garbage collector") \
- \
- product(uintx, HeapMaximumCompactionInterval, 20, \
- "How often should we maximally compact the heap (not allowing " \
- "any dead space)") \
- range(0, max_uintx) \
- \
- product(uintx, HeapFirstMaximumCompactionCount, 3, \
- "The collection count for the first maximum compaction") \
- range(0, max_uintx) \
- \
- product(bool, UseMaximumCompactionOnSystemGC, true, \
- "Use maximum compaction in the Parallel Old garbage collector " \
- "for a system GC") \
- \
- product(uintx, ParallelOldDeadWoodLimiterMean, 50, \
- "The mean used by the parallel compact dead wood " \
- "limiter (a number between 0-100)") \
- range(0, 100) \
- \
- product(uintx, ParallelOldDeadWoodLimiterStdDev, 80, \
- "The standard deviation used by the parallel compact dead wood " \
- "limiter (a number between 0-100)") \
- range(0, 100) \
- \
- product(uint, ParallelGCThreads, 0, \
- "Number of parallel threads parallel gc will use") \
- constraint(ParallelGCThreadsConstraintFunc,AfterErgo) \
- \
- diagnostic(bool, UseSemaphoreGCThreadsSynchronization, true, \
- "Use semaphore synchronization for the GC Threads, " \
- "instead of synchronization based on mutexes") \
- \
- product(bool, UseDynamicNumberOfGCThreads, true, \
- "Dynamically choose the number of threads up to a maximum of " \
- "ParallelGCThreads parallel collectors will use for garbage " \
- "collection work") \
- \
- diagnostic(bool, InjectGCWorkerCreationFailure, false, \
- "Inject thread creation failures for " \
- "UseDynamicNumberOfGCThreads") \
- \
- diagnostic(bool, ForceDynamicNumberOfGCThreads, false, \
- "Force dynamic selection of the number of " \
- "parallel threads parallel gc will use to aid debugging") \
- \
- product(size_t, HeapSizePerGCThread, ScaleForWordSize(64*M), \
- "Size of heap (bytes) per GC thread used in calculating the " \
- "number of GC threads") \
- range((size_t)os::vm_page_size(), (size_t)max_uintx) \
- \
- product(uint, ConcGCThreads, 0, \
- "Number of threads concurrent gc will use") \
- constraint(ConcGCThreadsConstraintFunc,AfterErgo) \
- \
- product(uint, GCTaskTimeStampEntries, 200, \
- "Number of time stamp entries per gc worker thread") \
- range(1, max_jint) \
- \
- product(bool, AlwaysTenure, false, \
- "Always tenure objects in eden (ParallelGC only)") \
- \
- product(bool, NeverTenure, false, \
- "Never tenure objects in eden, may tenure on overflow " \
- "(ParallelGC only)") \
- \
- product(bool, ScavengeBeforeFullGC, true, \
- "Scavenge youngest generation before each full GC.") \
- \
- product(bool, UseConcMarkSweepGC, false, \
- "Use Concurrent Mark-Sweep GC in the old generation") \
- \
- product(bool, ExplicitGCInvokesConcurrent, false, \
- "A System.gc() request invokes a concurrent collection; " \
- "(effective only when using concurrent collectors)") \
- \
- product(bool, GCLockerInvokesConcurrent, false, \
- "The exit of a JNI critical section necessitating a scavenge, " \
- "also kicks off a background concurrent collection") \
- \
- product(uintx, GCLockerEdenExpansionPercent, 5, \
- "How much the GC can expand the eden by while the GC locker " \
- "is active (as a percentage)") \
- range(0, 100) \
- \
- diagnostic(uintx, GCLockerRetryAllocationCount, 2, \
- "Number of times to retry allocations when " \
- "blocked by the GC locker") \
- range(0, max_uintx) \
- \
- product(bool, UseCMSBestFit, true, \
- "Use CMS best fit allocation strategy") \
- \
- product(uintx, ParallelGCBufferWastePct, 10, \
- "Wasted fraction of parallel allocation buffer") \
- range(0, 100) \
- \
- product(uintx, TargetPLABWastePct, 10, \
- "Target wasted space in last buffer as percent of overall " \
- "allocation") \
- range(1, 100) \
- \
- product(uintx, PLABWeight, 75, \
- "Percentage (0-100) used to weight the current sample when " \
- "computing exponentially decaying average for ResizePLAB") \
- range(0, 100) \
- \
- product(bool, ResizePLAB, true, \
- "Dynamically resize (survivor space) promotion LAB's") \
- \
- product(int, ParGCArrayScanChunk, 50, \
- "Scan a subset of object array and push remainder, if array is " \
- "bigger than this") \
- range(1, max_jint/3) \
- \
- product(bool, ParGCUseLocalOverflow, false, \
- "Instead of a global overflow list, use local overflow stacks") \
- \
- product(bool, ParGCTrimOverflow, true, \
- "Eagerly trim the local overflow lists " \
- "(when ParGCUseLocalOverflow)") \
- \
- notproduct(bool, ParGCWorkQueueOverflowALot, false, \
- "Simulate work queue overflow in ParNew") \
- \
- notproduct(uintx, ParGCWorkQueueOverflowInterval, 1000, \
- "An `interval' counter that determines how frequently " \
- "we simulate overflow; a smaller number increases frequency") \
- \
- product(uintx, ParGCDesiredObjsFromOverflowList, 20, \
- "The desired number of objects to claim from the overflow list") \
- range(0, max_uintx) \
- \
- diagnostic(uintx, ParGCStridesPerThread, 2, \
- "The number of strides per worker thread that we divide up the " \
- "card table scanning work into") \
- range(1, max_uintx) \
- constraint(ParGCStridesPerThreadConstraintFunc,AfterErgo) \
- \
- diagnostic(intx, ParGCCardsPerStrideChunk, 256, \
- "The number of cards in each chunk of the parallel chunks used " \
- "during card table scanning") \
- range(1, max_intx) \
- constraint(ParGCCardsPerStrideChunkConstraintFunc,AfterMemoryInit)\
- \
- product(uintx, OldPLABWeight, 50, \
- "Percentage (0-100) used to weight the current sample when " \
- "computing exponentially decaying average for resizing " \
- "OldPLABSize") \
- range(0, 100) \
- \
- product(bool, ResizeOldPLAB, true, \
- "Dynamically resize (old gen) promotion LAB's") \
- \
- product(size_t, CMSOldPLABMax, 1024, \
- "Maximum size of CMS gen promotion LAB caches per worker " \
- "per block size") \
- range(1, max_uintx) \
- constraint(CMSOldPLABMaxConstraintFunc,AfterMemoryInit) \
- \
- product(size_t, CMSOldPLABMin, 16, \
- "Minimum size of CMS gen promotion LAB caches per worker " \
- "per block size") \
- range(1, max_uintx) \
- constraint(CMSOldPLABMinConstraintFunc,AfterMemoryInit) \
- \
- product(uintx, CMSOldPLABNumRefills, 4, \
- "Nominal number of refills of CMS gen promotion LAB cache " \
- "per worker per block size") \
- range(1, max_uintx) \
- \
- product(bool, CMSOldPLABResizeQuicker, false, \
- "React on-the-fly during a scavenge to a sudden " \
- "change in block demand rate") \
- \
- product(uintx, CMSOldPLABToleranceFactor, 4, \
- "The tolerance of the phase-change detector for on-the-fly " \
- "PLAB resizing during a scavenge") \
- range(1, max_uintx) \
- \
- product(uintx, CMSOldPLABReactivityFactor, 2, \
- "The gain in the feedback loop for on-the-fly PLAB resizing " \
- "during a scavenge") \
- range(1, max_uintx) \
- \
- product(bool, AlwaysPreTouch, false, \
- "Force all freshly committed pages to be pre-touched") \
- \
- product(size_t, PreTouchParallelChunkSize, 1 * G, \
- "Per-thread chunk size for parallel memory pre-touch.") \
- range(1, SIZE_MAX / 2) \
- \
- product_pd(size_t, CMSYoungGenPerWorker, \
- "The maximum size of young gen chosen by default per GC worker " \
- "thread available") \
- range(1, max_uintx) \
- \
- product(uintx, CMSIncrementalSafetyFactor, 10, \
- "Percentage (0-100) used to add conservatism when computing the " \
- "duty cycle") \
- range(0, 100) \
- \
- product(uintx, CMSExpAvgFactor, 50, \
- "Percentage (0-100) used to weight the current sample when " \
- "computing exponential averages for CMS statistics") \
- range(0, 100) \
- \
- product(uintx, CMS_FLSWeight, 75, \
- "Percentage (0-100) used to weight the current sample when " \
- "computing exponentially decaying averages for CMS FLS " \
- "statistics") \
- range(0, 100) \
- \
- product(uintx, CMS_FLSPadding, 1, \
- "The multiple of deviation from mean to use for buffering " \
- "against volatility in free list demand") \
- range(0, max_juint) \
- \
- product(uintx, FLSCoalescePolicy, 2, \
- "CMS: aggressiveness level for coalescing, increasing " \
- "from 0 to 4") \
- range(0, 4) \
- \
- product(bool, FLSAlwaysCoalesceLarge, false, \
- "CMS: larger free blocks are always available for coalescing") \
- \
- product(double, FLSLargestBlockCoalesceProximity, 0.99, \
- "CMS: the smaller the percentage the greater the coalescing " \
- "force") \
- range(0.0, 1.0) \
- \
- product(double, CMSSmallCoalSurplusPercent, 1.05, \
- "CMS: the factor by which to inflate estimated demand of small " \
- "block sizes to prevent coalescing with an adjoining block") \
- range(0.0, DBL_MAX) \
- \
- product(double, CMSLargeCoalSurplusPercent, 0.95, \
- "CMS: the factor by which to inflate estimated demand of large " \
- "block sizes to prevent coalescing with an adjoining block") \
- range(0.0, DBL_MAX) \
- \
- product(double, CMSSmallSplitSurplusPercent, 1.10, \
- "CMS: the factor by which to inflate estimated demand of small " \
- "block sizes to prevent splitting to supply demand for smaller " \
- "blocks") \
- range(0.0, DBL_MAX) \
- \
- product(double, CMSLargeSplitSurplusPercent, 1.00, \
- "CMS: the factor by which to inflate estimated demand of large " \
- "block sizes to prevent splitting to supply demand for smaller " \
- "blocks") \
- range(0.0, DBL_MAX) \
- \
- product(bool, CMSExtrapolateSweep, false, \
- "CMS: cushion for block demand during sweep") \
- \
- product(uintx, CMS_SweepWeight, 75, \
- "Percentage (0-100) used to weight the current sample when " \
- "computing exponentially decaying average for inter-sweep " \
- "duration") \
- range(0, 100) \
- \
- product(uintx, CMS_SweepPadding, 1, \
- "The multiple of deviation from mean to use for buffering " \
- "against volatility in inter-sweep duration") \
- range(0, max_juint) \
- \
- product(uintx, CMS_SweepTimerThresholdMillis, 10, \
- "Skip block flux-rate sampling for an epoch unless inter-sweep " \
- "duration exceeds this threshold in milliseconds") \
- range(0, max_uintx) \
- \
- product(bool, CMSClassUnloadingEnabled, true, \
- "Whether class unloading enabled when using CMS GC") \
- \
- product(uintx, CMSClassUnloadingMaxInterval, 0, \
- "When CMS class unloading is enabled, the maximum CMS cycle " \
- "count for which classes may not be unloaded") \
- range(0, max_uintx) \
- \
- product(uintx, CMSIndexedFreeListReplenish, 4, \
- "Replenish an indexed free list with this number of chunks") \
- range(1, max_uintx) \
- \
- product(bool, CMSReplenishIntermediate, true, \
- "Replenish all intermediate free-list caches") \
- \
- product(bool, CMSSplitIndexedFreeListBlocks, true, \
- "When satisfying batched demand, split blocks from the " \
- "IndexedFreeList whose size is a multiple of requested size") \
- \
- product(bool, CMSLoopWarn, false, \
- "Warn in case of excessive CMS looping") \
- \
- /* where does the range max value of (max_jint - 1) come from? */ \
- product(size_t, MarkStackSizeMax, NOT_LP64(4*M) LP64_ONLY(512*M), \
- "Maximum size of marking stack") \
- range(1, (max_jint - 1)) \
- \
- product(size_t, MarkStackSize, NOT_LP64(32*K) LP64_ONLY(4*M), \
- "Size of marking stack") \
- constraint(MarkStackSizeConstraintFunc,AfterErgo) \
- \
- notproduct(bool, CMSMarkStackOverflowALot, false, \
- "Simulate frequent marking stack / work queue overflow") \
- \
- notproduct(uintx, CMSMarkStackOverflowInterval, 1000, \
- "An \"interval\" counter that determines how frequently " \
- "to simulate overflow; a smaller number increases frequency") \
- \
- product(uintx, CMSMaxAbortablePrecleanLoops, 0, \
- "Maximum number of abortable preclean iterations, if > 0") \
- range(0, max_uintx) \
- \
- product(intx, CMSMaxAbortablePrecleanTime, 5000, \
- "Maximum time in abortable preclean (in milliseconds)") \
- range(0, max_intx) \
- \
- product(uintx, CMSAbortablePrecleanMinWorkPerIteration, 100, \
- "Nominal minimum work per abortable preclean iteration") \
- range(0, max_uintx) \
- \
- manageable(intx, CMSAbortablePrecleanWaitMillis, 100, \
- "Time that we sleep between iterations when not given " \
- "enough work per iteration") \
- range(0, max_intx) \
- \
- /* 4096 = CardTable::card_size_in_words * BitsPerWord */ \
- product(size_t, CMSRescanMultiple, 32, \
- "Size (in cards) of CMS parallel rescan task") \
- range(1, SIZE_MAX / 4096) \
- constraint(CMSRescanMultipleConstraintFunc,AfterMemoryInit) \
- \
- /* 4096 = CardTable::card_size_in_words * BitsPerWord */ \
- product(size_t, CMSConcMarkMultiple, 32, \
- "Size (in cards) of CMS concurrent MT marking task") \
- range(1, SIZE_MAX / 4096) \
- constraint(CMSConcMarkMultipleConstraintFunc,AfterMemoryInit) \
- \
- product(bool, CMSAbortSemantics, false, \
- "Whether abort-on-overflow semantics is implemented") \
- \
- product(bool, CMSParallelInitialMarkEnabled, true, \
- "Use the parallel initial mark.") \
- \
- product(bool, CMSParallelRemarkEnabled, true, \
- "Whether parallel remark enabled (only if ParNewGC)") \
- \
- product(bool, CMSParallelSurvivorRemarkEnabled, true, \
- "Whether parallel remark of survivor space " \
- "enabled (effective only if CMSParallelRemarkEnabled)") \
- \
- product(bool, CMSPLABRecordAlways, true, \
- "Always record survivor space PLAB boundaries (effective only " \
- "if CMSParallelSurvivorRemarkEnabled)") \
- \
- product(bool, CMSEdenChunksRecordAlways, true, \
- "Always record eden chunks used for the parallel initial mark " \
- "or remark of eden") \
- \
- product(bool, CMSConcurrentMTEnabled, true, \
- "Whether multi-threaded concurrent work enabled " \
- "(effective only if ParNewGC)") \
- \
- product(bool, CMSPrecleaningEnabled, true, \
- "Whether concurrent precleaning enabled") \
- \
- product(uintx, CMSPrecleanIter, 3, \
- "Maximum number of precleaning iteration passes") \
- range(0, 9) \
- \
- product(uintx, CMSPrecleanDenominator, 3, \
- "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \
- "ratio") \
- range(1, max_uintx) \
- constraint(CMSPrecleanDenominatorConstraintFunc,AfterErgo) \
- \
- product(uintx, CMSPrecleanNumerator, 2, \
- "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \
- "ratio") \
- range(0, max_uintx-1) \
- constraint(CMSPrecleanNumeratorConstraintFunc,AfterErgo) \
- \
- product(bool, CMSPrecleanRefLists1, true, \
- "Preclean ref lists during (initial) preclean phase") \
- \
- product(bool, CMSPrecleanRefLists2, false, \
- "Preclean ref lists during abortable preclean phase") \
- \
- product(bool, CMSPrecleanSurvivors1, false, \
- "Preclean survivors during (initial) preclean phase") \
- \
- product(bool, CMSPrecleanSurvivors2, true, \
- "Preclean survivors during abortable preclean phase") \
- \
- product(uintx, CMSPrecleanThreshold, 1000, \
- "Do not iterate again if number of dirty cards is less than this")\
- range(100, max_uintx) \
- \
- product(bool, CMSCleanOnEnter, true, \
- "Clean-on-enter optimization for reducing number of dirty cards") \
- \
- product(uintx, CMSRemarkVerifyVariant, 1, \
- "Choose variant (1,2) of verification following remark") \
- range(1, 2) \
- \
- product(size_t, CMSScheduleRemarkEdenSizeThreshold, 2*M, \
- "If Eden size is below this, do not try to schedule remark") \
- range(0, max_uintx) \
- \
- product(uintx, CMSScheduleRemarkEdenPenetration, 50, \
- "The Eden occupancy percentage (0-100) at which " \
- "to try and schedule remark pause") \
- range(0, 100) \
- \
- product(uintx, CMSScheduleRemarkSamplingRatio, 5, \
- "Start sampling eden top at least before young gen " \
- "occupancy reaches 1/<ratio> of the size at which " \
- "we plan to schedule remark") \
- range(1, max_uintx) \
- \
- product(uintx, CMSSamplingGrain, 16*K, \
- "The minimum distance between eden samples for CMS (see above)") \
- range(ObjectAlignmentInBytes, max_uintx) \
- constraint(CMSSamplingGrainConstraintFunc,AfterMemoryInit) \
- \
- product(bool, CMSScavengeBeforeRemark, false, \
- "Attempt scavenge before the CMS remark step") \
- \
- product(uintx, CMSWorkQueueDrainThreshold, 10, \
- "Don't drain below this size per parallel worker/thief") \
- range(1, max_juint) \
- constraint(CMSWorkQueueDrainThresholdConstraintFunc,AfterErgo) \
- \
- manageable(intx, CMSWaitDuration, 2000, \
- "Time in milliseconds that CMS thread waits for young GC") \
- range(min_jint, max_jint) \
- \
- develop(uintx, CMSCheckInterval, 1000, \
- "Interval in milliseconds that CMS thread checks if it " \
- "should start a collection cycle") \
- \
- product(bool, CMSYield, true, \
- "Yield between steps of CMS") \
- \
- product(size_t, CMSBitMapYieldQuantum, 10*M, \
- "Bitmap operations should process at most this many bits " \
- "between yields") \
- range(1, max_uintx) \
- constraint(CMSBitMapYieldQuantumConstraintFunc,AfterMemoryInit) \
- \
- product(bool, CMSPrintChunksInDump, false, \
- "If logging for the \"gc\" and \"promotion\" tags is enabled on" \
- "trace level include more detailed information about the" \
- "free chunks") \
- \
- product(bool, CMSPrintObjectsInDump, false, \
- "If logging for the \"gc\" and \"promotion\" tags is enabled on" \
- "trace level include more detailed information about the" \
- "allocated objects") \
- \
- diagnostic(bool, FLSVerifyAllHeapReferences, false, \
- "Verify that all references across the FLS boundary " \
- "are to valid objects") \
- \
- diagnostic(bool, FLSVerifyLists, false, \
- "Do lots of (expensive) FreeListSpace verification") \
- \
- diagnostic(bool, FLSVerifyIndexTable, false, \
- "Do lots of (expensive) FLS index table verification") \
- \
develop(bool, FLSVerifyDictionary, false, \
"Do lots of (expensive) FLS dictionary verification") \
\
- develop(bool, VerifyBlockOffsetArray, false, \
- "Do (expensive) block offset array verification") \
- \
- diagnostic(bool, BlockOffsetArrayUseUnallocatedBlock, false, \
- "Maintain _unallocated_block in BlockOffsetArray " \
- "(currently applicable only to CMS collector)") \
- \
- product(intx, RefDiscoveryPolicy, 0, \
- "Select type of reference discovery policy: " \
- "reference-based(0) or referent-based(1)") \
- range(ReferenceProcessor::DiscoveryPolicyMin, \
- ReferenceProcessor::DiscoveryPolicyMax) \
- \
- product(bool, ParallelRefProcEnabled, false, \
- "Enable parallel reference processing whenever possible") \
- \
- product(bool, ParallelRefProcBalancingEnabled, true, \
- "Enable balancing of reference processing queues") \
- \
- product(uintx, CMSTriggerRatio, 80, \
- "Percentage of MinHeapFreeRatio in CMS generation that is " \
- "allocated before a CMS collection cycle commences") \
- range(0, 100) \
- \
- product(uintx, CMSBootstrapOccupancy, 50, \
- "Percentage CMS generation occupancy at which to " \
- "initiate CMS collection for bootstrapping collection stats") \
- range(0, 100) \
- \
- product(intx, CMSInitiatingOccupancyFraction, -1, \
- "Percentage CMS generation occupancy to start a CMS collection " \
- "cycle. A negative value means that CMSTriggerRatio is used") \
- range(min_intx, 100) \
- \
- product(uintx, InitiatingHeapOccupancyPercent, 45, \
- "The percent occupancy (IHOP) of the current old generation " \
- "capacity above which a concurrent mark cycle will be initiated " \
- "Its value may change over time if adaptive IHOP is enabled, " \
- "otherwise the value remains constant. " \
- "In the latter case a value of 0 will result as frequent as " \
- "possible concurrent marking cycles. A value of 100 disables " \
- "concurrent marking. " \
- "Fragmentation waste in the old generation is not considered " \
- "free space in this calculation. (G1 collector only)") \
- range(0, 100) \
- \
- manageable(intx, CMSTriggerInterval, -1, \
- "Commence a CMS collection cycle (at least) every so many " \
- "milliseconds (0 permanently, -1 disabled)") \
- range(-1, max_intx) \
- \
- product(bool, UseCMSInitiatingOccupancyOnly, false, \
- "Only use occupancy as a criterion for starting a CMS collection")\
- \
- product(uintx, CMSIsTooFullPercentage, 98, \
- "An absolute ceiling above which CMS will always consider the " \
- "unloading of classes when class unloading is enabled") \
- range(0, 100) \
- \
- develop(bool, CMSTestInFreeList, false, \
- "Check if the coalesced range is already in the " \
- "free lists as claimed") \
- \
- notproduct(bool, CMSVerifyReturnedBytes, false, \
- "Check that all the garbage collected was returned to the " \
- "free lists") \
- \
- notproduct(bool, ScavengeALot, false, \
- "Force scavenge at every Nth exit from the runtime system " \
- "(N=ScavengeALotInterval)") \
- \
- develop(bool, FullGCALot, false, \
- "Force full gc at every Nth exit from the runtime system " \
- "(N=FullGCALotInterval)") \
- \
- notproduct(bool, GCALotAtAllSafepoints, false, \
- "Enforce ScavengeALot/GCALot at all potential safepoints") \
- \
- notproduct(bool, PromotionFailureALot, false, \
- "Use promotion failure handling on every youngest generation " \
- "collection") \
- \
- develop(uintx, PromotionFailureALotCount, 1000, \
- "Number of promotion failures occurring at PLAB " \
- "refill attempts (ParNew) or promotion attempts " \
- "(other young collectors)") \
- \
- develop(uintx, PromotionFailureALotInterval, 5, \
- "Total collections between promotion failures a lot") \
- \
- experimental(uintx, WorkStealingSleepMillis, 1, \
- "Sleep time when sleep is used for yields") \
- \
- experimental(uintx, WorkStealingYieldsBeforeSleep, 5000, \
- "Number of yields before a sleep is done during work stealing") \
- \
- experimental(uintx, WorkStealingHardSpins, 4096, \
- "Number of iterations in a spin loop between checks on " \
- "time out of hard spin") \
- \
- experimental(uintx, WorkStealingSpinToYieldRatio, 10, \
- "Ratio of hard spins to calls to yield") \
- \
- develop(uintx, ObjArrayMarkingStride, 2048, \
- "Number of object array elements to push onto the marking stack " \
- "before pushing a continuation entry") \
- \
- develop(bool, MetadataAllocationFailALot, false, \
- "Fail metadata allocations at intervals controlled by " \
- "MetadataAllocationFailALotInterval") \
- \
- develop(uintx, MetadataAllocationFailALotInterval, 1000, \
- "Metadata allocation failure a lot interval") \
- \
- notproduct(bool, ExecuteInternalVMTests, false, \
- "Enable execution of internal VM tests") \
- \
- notproduct(bool, VerboseInternalVMTests, false, \
- "Turn on logging for internal VM tests.") \
- \
- product(bool, ExecutingUnitTests, false, \
- "Whether the JVM is running unit tests or not") \
- \
- product_pd(bool, UseTLAB, "Use thread-local object allocation") \
- \
- product_pd(bool, ResizeTLAB, \
- "Dynamically resize TLAB size for threads") \
- \
- product(bool, ZeroTLAB, false, \
- "Zero out the newly created TLAB") \
- \
- product(bool, TLABStats, true, \
- "Provide more detailed and expensive TLAB statistics.") \
- \
- product_pd(bool, NeverActAsServerClassMachine, \
- "Never act like a server-class machine") \
- \
- product(bool, AlwaysActAsServerClassMachine, false, \
- "Always act like a server-class machine") \
- \
- product_pd(uint64_t, MaxRAM, \
- "Real memory size (in bytes) used to set maximum heap size") \
- range(0, 0XFFFFFFFFFFFFFFFF) \
- \
- product(bool, AggressiveHeap, false, \
- "Optimize heap options for long-running memory intensive apps") \
- \
- product(size_t, ErgoHeapSizeLimit, 0, \
- "Maximum ergonomically set heap size (in bytes); zero means use " \
- "MaxRAM * MaxRAMPercentage / 100") \
- range(0, max_uintx) \
- \
- product(uintx, MaxRAMFraction, 4, \
- "Maximum fraction (1/n) of real memory used for maximum heap " \
- "size. " \
- "Deprecated, use MaxRAMPercentage instead") \
- range(1, max_uintx) \
- \
- product(uintx, MinRAMFraction, 2, \
- "Minimum fraction (1/n) of real memory used for maximum heap " \
- "size on systems with small physical memory size. " \
- "Deprecated, use MinRAMPercentage instead") \
- range(1, max_uintx) \
- \
- product(uintx, InitialRAMFraction, 64, \
- "Fraction (1/n) of real memory used for initial heap size. " \
- "Deprecated, use InitialRAMPercentage instead") \
- range(1, max_uintx) \
- \
- product(double, MaxRAMPercentage, 25.0, \
- "Maximum percentage of real memory used for maximum heap size") \
- range(0.0, 100.0) \
- \
- product(double, MinRAMPercentage, 50.0, \
- "Minimum percentage of real memory used for maximum heap" \
- "size on systems with small physical memory size") \
- range(0.0, 100.0) \
- \
- product(double, InitialRAMPercentage, 1.5625, \
- "Percentage of real memory used for initial heap size") \
- range(0.0, 100.0) \
- \
- product(int, ActiveProcessorCount, -1, \
- "Specify the CPU count the VM should use and report as active") \
- \
- develop(uintx, MaxVirtMemFraction, 2, \
- "Maximum fraction (1/n) of virtual memory used for ergonomically "\
- "determining maximum heap size") \
- \
- product(bool, UseAdaptiveSizePolicy, true, \
- "Use adaptive generation sizing policies") \
- \
- product(bool, UsePSAdaptiveSurvivorSizePolicy, true, \
- "Use adaptive survivor sizing policies") \
- \
- product(bool, UseAdaptiveGenerationSizePolicyAtMinorCollection, true, \
- "Use adaptive young-old sizing policies at minor collections") \
- \
- product(bool, UseAdaptiveGenerationSizePolicyAtMajorCollection, true, \
- "Use adaptive young-old sizing policies at major collections") \
- \
- product(bool, UseAdaptiveSizePolicyWithSystemGC, false, \
- "Include statistics from System.gc() for adaptive size policy") \
- \
- product(bool, UseAdaptiveGCBoundary, false, \
- "Allow young-old boundary to move") \
- \
- develop(intx, PSAdaptiveSizePolicyResizeVirtualSpaceAlot, -1, \
- "Resize the virtual spaces of the young or old generations") \
- range(-1, 1) \
- \
- product(uintx, AdaptiveSizeThroughPutPolicy, 0, \
- "Policy for changing generation size for throughput goals") \
- range(0, 1) \
- \
- product(uintx, AdaptiveSizePolicyInitializingSteps, 20, \
- "Number of steps where heuristics is used before data is used") \
- range(0, max_uintx) \
- \
- develop(uintx, AdaptiveSizePolicyReadyThreshold, 5, \
- "Number of collections before the adaptive sizing is started") \
- \
- product(uintx, AdaptiveSizePolicyOutputInterval, 0, \
- "Collection interval for printing information; zero means never") \
- range(0, max_uintx) \
- \
- product(bool, UseAdaptiveSizePolicyFootprintGoal, true, \
- "Use adaptive minimum footprint as a goal") \
- \
- product(uintx, AdaptiveSizePolicyWeight, 10, \
- "Weight given to exponential resizing, between 0 and 100") \
- range(0, 100) \
- \
- product(uintx, AdaptiveTimeWeight, 25, \
- "Weight given to time in adaptive policy, between 0 and 100") \
- range(0, 100) \
- \
- product(uintx, PausePadding, 1, \
- "How much buffer to keep for pause time") \
- range(0, max_juint) \
- \
- product(uintx, PromotedPadding, 3, \
- "How much buffer to keep for promotion failure") \
- range(0, max_juint) \
- \
- product(uintx, SurvivorPadding, 3, \
- "How much buffer to keep for survivor overflow") \
- range(0, max_juint) \
- \
- product(uintx, ThresholdTolerance, 10, \
- "Allowed collection cost difference between generations") \
- range(0, 100) \
- \
- product(uintx, AdaptiveSizePolicyCollectionCostMargin, 50, \
- "If collection costs are within margin, reduce both by full " \
- "delta") \
- range(0, 100) \
- \
- product(uintx, YoungGenerationSizeIncrement, 20, \
- "Adaptive size percentage change in young generation") \
- range(0, 100) \
- \
- product(uintx, YoungGenerationSizeSupplement, 80, \
- "Supplement to YoungedGenerationSizeIncrement used at startup") \
- range(0, 100) \
- \
- product(uintx, YoungGenerationSizeSupplementDecay, 8, \
- "Decay factor to YoungedGenerationSizeSupplement") \
- range(1, max_uintx) \
- \
- product(uintx, TenuredGenerationSizeIncrement, 20, \
- "Adaptive size percentage change in tenured generation") \
- range(0, 100) \
- \
- product(uintx, TenuredGenerationSizeSupplement, 80, \
- "Supplement to TenuredGenerationSizeIncrement used at startup") \
- range(0, 100) \
- \
- product(uintx, TenuredGenerationSizeSupplementDecay, 2, \
- "Decay factor to TenuredGenerationSizeIncrement") \
- range(1, max_uintx) \
- \
- product(uintx, MaxGCPauseMillis, max_uintx - 1, \
- "Adaptive size policy maximum GC pause time goal in millisecond, "\
- "or (G1 Only) the maximum GC time per MMU time slice") \
- range(1, max_uintx - 1) \
- constraint(MaxGCPauseMillisConstraintFunc,AfterErgo) \
- \
- product(uintx, GCPauseIntervalMillis, 0, \
- "Time slice for MMU specification") \
- constraint(GCPauseIntervalMillisConstraintFunc,AfterErgo) \
- \
- product(uintx, MaxGCMinorPauseMillis, max_uintx, \
- "Adaptive size policy maximum GC minor pause time goal " \
- "in millisecond") \
- range(0, max_uintx) \
- \
- product(uintx, GCTimeRatio, 99, \
- "Adaptive size policy application time to GC time ratio") \
- range(0, max_juint) \
- \
- product(uintx, AdaptiveSizeDecrementScaleFactor, 4, \
- "Adaptive size scale down factor for shrinking") \
- range(1, max_uintx) \
- \
- product(bool, UseAdaptiveSizeDecayMajorGCCost, true, \
- "Adaptive size decays the major cost for long major intervals") \
- \
- product(uintx, AdaptiveSizeMajorGCDecayTimeScale, 10, \
- "Time scale over which major costs decay") \
- range(0, max_uintx) \
- \
- product(uintx, MinSurvivorRatio, 3, \
- "Minimum ratio of young generation/survivor space size") \
- range(3, max_uintx) \
- \
- product(uintx, InitialSurvivorRatio, 8, \
- "Initial ratio of young generation/survivor space size") \
- range(0, max_uintx) \
- \
- product(size_t, BaseFootPrintEstimate, 256*M, \
- "Estimate of footprint other than Java Heap") \
- range(0, max_uintx) \
- \
- product(bool, UseGCOverheadLimit, true, \
- "Use policy to limit of proportion of time spent in GC " \
- "before an OutOfMemory error is thrown") \
- \
- product(uintx, GCTimeLimit, 98, \
- "Limit of the proportion of time spent in GC before " \
- "an OutOfMemoryError is thrown (used with GCHeapFreeLimit)") \
- range(0, 100) \
- \
- product(uintx, GCHeapFreeLimit, 2, \
- "Minimum percentage of free space after a full GC before an " \
- "OutOfMemoryError is thrown (used with GCTimeLimit)") \
- range(0, 100) \
- \
- develop(uintx, AdaptiveSizePolicyGCTimeLimitThreshold, 5, \
- "Number of consecutive collections before gc time limit fires") \
- range(1, max_uintx) \
- \
- product(intx, PrefetchCopyIntervalInBytes, -1, \
- "How far ahead to prefetch destination area (<= 0 means off)") \
- range(-1, max_jint) \
- \
- product(intx, PrefetchScanIntervalInBytes, -1, \
- "How far ahead to prefetch scan area (<= 0 means off)") \
- range(-1, max_jint) \
- \
- product(intx, PrefetchFieldsAhead, -1, \
- "How many fields ahead to prefetch in oop scan (<= 0 means off)") \
- range(-1, max_jint) \
- \
- diagnostic(bool, VerifyDuringStartup, false, \
- "Verify memory system before executing any Java code " \
- "during VM initialization") \
- \
- diagnostic(bool, VerifyBeforeExit, trueInDebug, \
- "Verify system before exiting") \
- \
- diagnostic(bool, VerifyBeforeGC, false, \
- "Verify memory system before GC") \
- \
- diagnostic(bool, VerifyAfterGC, false, \
- "Verify memory system after GC") \
- \
- diagnostic(bool, VerifyDuringGC, false, \
- "Verify memory system during GC (between phases)") \
- \
- diagnostic(ccstrlist, VerifyGCType, "", \
- "GC type(s) to verify when Verify*GC is enabled." \
- "Available types are collector specific.") \
- \
- diagnostic(ccstrlist, VerifySubSet, "", \
- "Memory sub-systems to verify when Verify*GC flag(s) " \
- "are enabled. One or more sub-systems can be specified " \
- "in a comma separated string. Sub-systems are: " \
- "threads, heap, symbol_table, string_table, codecache, " \
- "dictionary, classloader_data_graph, metaspace, jni_handles, " \
- "codecache_oops") \
- \
- diagnostic(bool, GCParallelVerificationEnabled, true, \
- "Enable parallel memory system verification") \
- \
- diagnostic(bool, DeferInitialCardMark, false, \
- "When +ReduceInitialCardMarks, explicitly defer any that " \
- "may arise from new_pre_store_barrier") \
- \
- product(bool, UseCondCardMark, false, \
- "Check for already marked card before updating card table") \
- \
- diagnostic(bool, VerifyRememberedSets, false, \
- "Verify GC remembered sets") \
- \
- diagnostic(bool, VerifyObjectStartArray, true, \
- "Verify GC object start array if verify before/after") \
- \
- product(bool, DisableExplicitGC, false, \
- "Ignore calls to System.gc()") \
\
notproduct(bool, CheckMemoryInitialization, false, \
"Check memory initialization") \
\
- diagnostic(bool, BindCMSThreadToCPU, false, \
- "Bind CMS Thread to CPU if possible") \
- \
- diagnostic(uintx, CPUForCMSThread, 0, \
- "When BindCMSThreadToCPU is true, the CPU to bind CMS thread to") \
- range(0, max_juint) \
- \
- product(bool, BindGCTaskThreadsToCPUs, false, \
- "Bind GCTaskThreads to CPUs if possible") \
- \
- product(bool, UseGCTaskAffinity, false, \
- "Use worker affinity when asking for GCTasks") \
- \
product(uintx, ProcessDistributionStride, 4, \
"Stride through processors when distributing processes") \
range(0, max_juint) \
\
- product(uintx, CMSCoordinatorYieldSleepCount, 10, \
- "Number of times the coordinator GC thread will sleep while " \
- "yielding before giving up and resuming GC") \
- range(0, max_juint) \
- \
- product(uintx, CMSYieldSleepCount, 0, \
- "Number of times a GC thread (minus the coordinator) " \
- "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") \
- range(0, max_intx) \
- \
develop(bool, TraceFinalizerRegistration, false, \
"Trace registration of final references") \
\
@@ -2336,18 +1418,6 @@
manageable(bool, PrintClassHistogram, false, \
"Print a histogram of class instances") \
\
- develop(bool, TraceGCTaskManager, false, \
- "Trace actions of the GC task manager") \
- \
- develop(bool, TraceGCTaskQueue, false, \
- "Trace actions of the GC task queues") \
- \
- develop(bool, TraceParallelOldGCMarkingPhase, false, \
- "Trace marking phase in ParallelOldGC") \
- \
- develop(bool, TraceParallelOldGCDensePrefix, false, \
- "Trace dense prefix computation for ParallelOldGC") \
- \
develop(bool, IgnoreLibthreadGPFault, false, \
"Suppress workaround for libthread GP fault") \
\
@@ -2982,19 +2052,6 @@
"(+ProfileIntervals)") \
range(0, max_intx) \
\
- notproduct(intx, ScavengeALotInterval, 1, \
- "Interval between which scavenge will occur with +ScavengeALot") \
- \
- notproduct(intx, FullGCALotInterval, 1, \
- "Interval between which full gc will occur with +FullGCALot") \
- \
- notproduct(intx, FullGCALotStart, 0, \
- "For which invocation to start FullGCAlot") \
- \
- notproduct(intx, FullGCALotDummies, 32*K, \
- "Dummy object allocated with +FullGCALot, forcing all objects " \
- "to move") \
- \
develop(intx, DontYieldALotInterval, 10, \
"Interval between which yields will be dropped (milliseconds)") \
\
@@ -3064,88 +2121,6 @@
"Size in K to allocate for the Profile Nodes of each thread") \
range(0, 1024) \
\
- /* gc parameters */ \
- product(size_t, InitialHeapSize, 0, \
- "Initial heap size (in bytes); zero means use ergonomics") \
- constraint(InitialHeapSizeConstraintFunc,AfterErgo) \
- \
- product(size_t, MaxHeapSize, ScaleForWordSize(96*M), \
- "Maximum heap size (in bytes)") \
- constraint(MaxHeapSizeConstraintFunc,AfterErgo) \
- \
- product(size_t, OldSize, ScaleForWordSize(4*M), \
- "Initial tenured generation size (in bytes)") \
- range(0, max_uintx) \
- \
- product(size_t, NewSize, ScaleForWordSize(1*M), \
- "Initial new generation size (in bytes)") \
- constraint(NewSizeConstraintFunc,AfterErgo) \
- \
- product(size_t, MaxNewSize, max_uintx, \
- "Maximum new generation size (in bytes), max_uintx means set " \
- "ergonomically") \
- range(0, max_uintx) \
- \
- product_pd(size_t, HeapBaseMinAddress, \
- "OS specific low limit for heap base address") \
- constraint(HeapBaseMinAddressConstraintFunc,AfterErgo) \
- \
- product(size_t, PretenureSizeThreshold, 0, \
- "Maximum size in bytes of objects allocated in DefNew " \
- "generation; zero means no maximum") \
- range(0, max_uintx) \
- \
- product(size_t, MinTLABSize, 2*K, \
- "Minimum allowed TLAB size (in bytes)") \
- range(1, max_uintx/2) \
- constraint(MinTLABSizeConstraintFunc,AfterMemoryInit) \
- \
- product(size_t, TLABSize, 0, \
- "Starting TLAB size (in bytes); zero means set ergonomically") \
- constraint(TLABSizeConstraintFunc,AfterMemoryInit) \
- \
- product(size_t, YoungPLABSize, 4096, \
- "Size of young gen promotion LAB's (in HeapWords)") \
- constraint(YoungPLABSizeConstraintFunc,AfterMemoryInit) \
- \
- product(size_t, OldPLABSize, 1024, \
- "Size of old gen promotion LAB's (in HeapWords), or Number " \
- "of blocks to attempt to claim when refilling CMS LAB's") \
- constraint(OldPLABSizeConstraintFunc,AfterMemoryInit) \
- \
- product(uintx, TLABAllocationWeight, 35, \
- "Allocation averaging weight") \
- range(0, 100) \
- \
- /* Limit the lower bound of this flag to 1 as it is used */ \
- /* in a division expression. */ \
- product(uintx, TLABWasteTargetPercent, 1, \
- "Percentage of Eden that can be wasted") \
- range(1, 100) \
- \
- product(uintx, TLABRefillWasteFraction, 64, \
- "Maximum TLAB waste at a refill (internal fragmentation)") \
- range(1, max_juint) \
- \
- product(uintx, TLABWasteIncrement, 4, \
- "Increment allowed waste at slow allocation") \
- range(0, max_jint) \
- constraint(TLABWasteIncrementConstraintFunc,AfterMemoryInit) \
- \
- product(uintx, SurvivorRatio, 8, \
- "Ratio of eden/survivor space size") \
- range(1, max_uintx-2) \
- constraint(SurvivorRatioConstraintFunc,AfterMemoryInit) \
- \
- product(uintx, NewRatio, 2, \
- "Ratio of old/new generation sizes") \
- range(0, max_uintx-1) \
- \
- product_pd(size_t, NewSizeThreadIncrease, \
- "Additional size added to desired new generation size per " \
- "non-daemon thread (in bytes)") \
- range(0, max_uintx) \
- \
product_pd(size_t, MetaspaceSize, \
"Initial threshold (in bytes) at which a garbage collection " \
"is done to reduce Metaspace usage") \
@@ -3208,63 +2183,6 @@
"The maximum expansion of Metaspace without full GC (in bytes)") \
range(0, max_uintx) \
\
- product(uintx, QueuedAllocationWarningCount, 0, \
- "Number of times an allocation that queues behind a GC " \
- "will retry before printing a warning") \
- range(0, max_uintx) \
- \
- diagnostic(uintx, VerifyGCStartAt, 0, \
- "GC invoke count where +VerifyBefore/AfterGC kicks in") \
- range(0, max_uintx) \
- \
- diagnostic(intx, VerifyGCLevel, 0, \
- "Generation level at which to start +VerifyBefore/AfterGC") \
- range(0, 1) \
- \
- product(uintx, MaxTenuringThreshold, 15, \
- "Maximum value for tenuring threshold") \
- range(0, markOopDesc::max_age + 1) \
- constraint(MaxTenuringThresholdConstraintFunc,AfterErgo) \
- \
- product(uintx, InitialTenuringThreshold, 7, \
- "Initial value for tenuring threshold") \
- range(0, markOopDesc::max_age + 1) \
- constraint(InitialTenuringThresholdConstraintFunc,AfterErgo) \
- \
- product(uintx, TargetSurvivorRatio, 50, \
- "Desired percentage of survivor space used after scavenge") \
- range(0, 100) \
- \
- product(uintx, MarkSweepDeadRatio, 5, \
- "Percentage (0-100) of the old gen allowed as dead wood. " \
- "Serial mark sweep treats this as both the minimum and maximum " \
- "value. " \
- "CMS uses this value only if it falls back to mark sweep. " \
- "Par compact uses a variable scale based on the density of the " \
- "generation and treats this as the maximum value when the heap " \
- "is either completely full or completely empty. Par compact " \
- "also has a smaller default value; see arguments.cpp.") \
- range(0, 100) \
- \
- product(uint, MarkSweepAlwaysCompactCount, 4, \
- "How often should we fully compact the heap (ignoring the dead " \
- "space parameters)") \
- range(1, max_juint) \
- \
- develop(uintx, GCExpandToAllocateDelayMillis, 0, \
- "Delay between expansion and allocation (in milliseconds)") \
- \
- develop(uintx, GCWorkerDelayMillis, 0, \
- "Delay in scheduling GC workers (in milliseconds)") \
- \
- product(bool, PSChunkLargeArrays, true, \
- "Process large arrays in chunks") \
- \
- product(uintx, GCDrainStackTargetSize, 64, \
- "Number of entries we will try to leave on the stack " \
- "during parallel gc") \
- range(0, max_juint) \
- \
/* stack parameters */ \
product_pd(intx, StackYellowPages, \
"Number of yellow zone (recoverable overflows) pages of size " \
@@ -4066,7 +2984,52 @@
"On internal errors, include registers in error report.") \
\
-
+#define VM_FLAGS(develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+ \
+ RUNTIME_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
+ \
+ GC_FLAGS( \
+ develop, \
+ develop_pd, \
+ product, \
+ product_pd, \
+ diagnostic, \
+ diagnostic_pd, \
+ experimental, \
+ notproduct, \
+ manageable, \
+ product_rw, \
+ lp64_product, \
+ range, \
+ constraint, \
+ writeable) \
/*
* Macros for factoring of globals
@@ -4126,20 +3089,20 @@
#define IGNORE_WRITEABLE(type)
-RUNTIME_FLAGS(DECLARE_DEVELOPER_FLAG, \
- DECLARE_PD_DEVELOPER_FLAG, \
- DECLARE_PRODUCT_FLAG, \
- DECLARE_PD_PRODUCT_FLAG, \
- DECLARE_DIAGNOSTIC_FLAG, \
- DECLARE_PD_DIAGNOSTIC_FLAG, \
- DECLARE_EXPERIMENTAL_FLAG, \
- DECLARE_NOTPRODUCT_FLAG, \
- DECLARE_MANAGEABLE_FLAG, \
- DECLARE_PRODUCT_RW_FLAG, \
- DECLARE_LP64_PRODUCT_FLAG, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
+VM_FLAGS(DECLARE_DEVELOPER_FLAG, \
+ DECLARE_PD_DEVELOPER_FLAG, \
+ DECLARE_PRODUCT_FLAG, \
+ DECLARE_PD_PRODUCT_FLAG, \
+ DECLARE_DIAGNOSTIC_FLAG, \
+ DECLARE_PD_DIAGNOSTIC_FLAG, \
+ DECLARE_EXPERIMENTAL_FLAG, \
+ DECLARE_NOTPRODUCT_FLAG, \
+ DECLARE_MANAGEABLE_FLAG, \
+ DECLARE_PRODUCT_RW_FLAG, \
+ DECLARE_LP64_PRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT, \
+ IGNORE_WRITEABLE)
RUNTIME_OS_FLAGS(DECLARE_DEVELOPER_FLAG, \
DECLARE_PD_DEVELOPER_FLAG, \
--- a/src/hotspot/share/runtime/globals_extension.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/globals_extension.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,9 +28,6 @@
#include "runtime/globals.hpp"
#include "utilities/macros.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1_globals.hpp"
-#endif
#if INCLUDE_JVMCI
#include "jvmci/jvmci_globals.hpp"
#endif
@@ -96,21 +93,22 @@
#define ARCH_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
typedef enum {
- RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, \
- RUNTIME_PD_DEVELOP_FLAG_MEMBER, \
- RUNTIME_PRODUCT_FLAG_MEMBER, \
- RUNTIME_PD_PRODUCT_FLAG_MEMBER, \
- RUNTIME_DIAGNOSTIC_FLAG_MEMBER, \
- RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER, \
- RUNTIME_EXPERIMENTAL_FLAG_MEMBER, \
- RUNTIME_NOTPRODUCT_FLAG_MEMBER, \
- RUNTIME_MANAGEABLE_FLAG_MEMBER, \
- RUNTIME_PRODUCT_RW_FLAG_MEMBER, \
- RUNTIME_LP64_PRODUCT_FLAG_MEMBER, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
- RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, \
+ VM_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, \
+ RUNTIME_PD_DEVELOP_FLAG_MEMBER, \
+ RUNTIME_PRODUCT_FLAG_MEMBER, \
+ RUNTIME_PD_PRODUCT_FLAG_MEMBER, \
+ RUNTIME_DIAGNOSTIC_FLAG_MEMBER, \
+ RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER, \
+ RUNTIME_EXPERIMENTAL_FLAG_MEMBER, \
+ RUNTIME_NOTPRODUCT_FLAG_MEMBER, \
+ RUNTIME_MANAGEABLE_FLAG_MEMBER, \
+ RUNTIME_PRODUCT_RW_FLAG_MEMBER, \
+ RUNTIME_LP64_PRODUCT_FLAG_MEMBER, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT, \
+ IGNORE_WRITEABLE)
+
+ RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, \
RUNTIME_PD_DEVELOP_FLAG_MEMBER, \
RUNTIME_PRODUCT_FLAG_MEMBER, \
RUNTIME_PD_PRODUCT_FLAG_MEMBER, \
@@ -120,21 +118,6 @@
IGNORE_RANGE, \
IGNORE_CONSTRAINT, \
IGNORE_WRITEABLE)
-#if INCLUDE_ALL_GCS
- G1_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, \
- RUNTIME_PD_DEVELOP_FLAG_MEMBER, \
- RUNTIME_PRODUCT_FLAG_MEMBER, \
- RUNTIME_PD_PRODUCT_FLAG_MEMBER, \
- RUNTIME_DIAGNOSTIC_FLAG_MEMBER, \
- RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER, \
- RUNTIME_EXPERIMENTAL_FLAG_MEMBER, \
- RUNTIME_NOTPRODUCT_FLAG_MEMBER, \
- RUNTIME_MANAGEABLE_FLAG_MEMBER, \
- RUNTIME_PRODUCT_RW_FLAG_MEMBER, \
- IGNORE_RANGE, \
- IGNORE_CONSTRAINT, \
- IGNORE_WRITEABLE)
-#endif // INCLUDE_ALL_GCS
#if INCLUDE_JVMCI
JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_MEMBER, \
JVMCI_PD_DEVELOP_FLAG_MEMBER, \
@@ -239,20 +222,21 @@
#define ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type),
typedef enum {
- RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE)
+ VM_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE,
+ RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
+ RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE,
+ RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
+ RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
+ RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
+ RUNTIME_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
+ RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
+ RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE,
+ RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE,
+ RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT,
+ IGNORE_WRITEABLE)
+
RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE,
RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE,
@@ -263,21 +247,6 @@
IGNORE_RANGE,
IGNORE_CONSTRAINT,
IGNORE_WRITEABLE)
-#if INCLUDE_ALL_GCS
- G1_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PD_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE,
- IGNORE_RANGE,
- IGNORE_CONSTRAINT,
- IGNORE_WRITEABLE)
-#endif // INCLUDE_ALL_GCS
#if INCLUDE_JVMCI
JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_MEMBER_WITH_TYPE,
JVMCI_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
--- a/src/hotspot/share/runtime/init.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/init.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -58,14 +58,8 @@
void os_init_globals(); // depends on VM_Version_init, before universe_init
void stubRoutines_init1();
jint universe_init(); // depends on codeCache_init and stubRoutines_init
-#if INCLUDE_ALL_GCS
// depends on universe_init, must be before interpreter_init (currently only on SPARC)
-#ifndef ZERO
-void g1_barrier_stubs_init() NOT_SPARC({});
-#else
-void g1_barrier_stubs_init() {};
-#endif
-#endif
+void gc_barrier_stubs_init();
void interpreter_init(); // before any methods loaded
void invocationCounter_init(); // before any methods loaded
void marksweep_init();
@@ -120,9 +114,7 @@
if (status != JNI_OK)
return status;
-#if INCLUDE_ALL_GCS
- g1_barrier_stubs_init(); // depends on universe_init, must be before interpreter_init
-#endif
+ gc_barrier_stubs_init(); // depends on universe_init, must be before interpreter_init
interpreter_init(); // before any methods loaded
invocationCounter_init(); // before any methods loaded
marksweep_init();
--- a/src/hotspot/share/runtime/interfaceSupport.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/interfaceSupport.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -25,7 +25,6 @@
#include "precompiled.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/atomic.hpp"
#include "runtime/frame.inline.hpp"
--- a/src/hotspot/share/runtime/java.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/java.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -31,7 +31,6 @@
#include "code/codeCache.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compilerOracle.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#if INCLUDE_JVMCI
#include "jvmci/jvmciCompiler.hpp"
--- a/src/hotspot/share/runtime/mutexLocker.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/mutexLocker.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -48,6 +48,8 @@
Mutex* JNIWeakAlloc_lock = NULL;
Mutex* JNIWeakActive_lock = NULL;
Mutex* JNIHandleBlockFreeList_lock = NULL;
+Mutex* VMWeakAlloc_lock = NULL;
+Mutex* VMWeakActive_lock = NULL;
Mutex* ResolvedMethodTable_lock = NULL;
Mutex* JmethodIdCreation_lock = NULL;
Mutex* JfieldIdCreation_lock = NULL;
@@ -260,6 +262,8 @@
def(JNIGlobalActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
def(JNIWeakAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
def(JNIWeakActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
+ def(VMWeakAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
+ def(VMWeakActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
def(JNICritical_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_always); // used for JNI critical regions
def(AdapterHandlerLibrary_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_always);
--- a/src/hotspot/share/runtime/mutexLocker.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/mutexLocker.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -41,6 +41,8 @@
extern Mutex* JNIWeakAlloc_lock; // JNI weak storage allocate list lock
extern Mutex* JNIWeakActive_lock; // JNI weak storage active list lock
extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list
+extern Mutex* VMWeakAlloc_lock; // VM Weak Handles storage allocate list lock
+extern Mutex* VMWeakActive_lock; // VM Weak Handles storage active list lock
extern Mutex* ResolvedMethodTable_lock; // a lock on the ResolvedMethodTable updates
extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers
extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers
--- a/src/hotspot/share/runtime/sharedRuntime.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/sharedRuntime.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -36,6 +36,7 @@
#include "compiler/abstractCompiler.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/disassembler.hpp"
+#include "gc/shared/barrierSet.hpp"
#include "gc/shared/gcLocker.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
@@ -75,6 +76,9 @@
#ifdef COMPILER1
#include "c1/c1_Runtime1.hpp"
#endif
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1ThreadLocalData.hpp"
+#endif // INCLUDE_ALL_GCS
// Shared stub locations
RuntimeStub* SharedRuntime::_wrong_method_blob;
@@ -214,12 +218,12 @@
}
assert(oopDesc::is_oop(orig, true /* ignore mark word */), "Error");
// store the original value that was in the field reference
- thread->satb_mark_queue().enqueue(orig);
+ G1ThreadLocalData::satb_mark_queue(thread).enqueue(orig);
JRT_END
// G1 write-barrier post: executed after a pointer store.
JRT_LEAF(void, SharedRuntime::g1_wb_post(void* card_addr, JavaThread* thread))
- thread->dirty_card_queue().enqueue(card_addr);
+ G1ThreadLocalData::dirty_card_queue(thread).enqueue(card_addr);
JRT_END
#endif // INCLUDE_ALL_GCS
@@ -3146,6 +3150,6 @@
oop new_obj = thread->vm_result();
if (new_obj == NULL) return;
- BarrierSet *bs = Universe::heap()->barrier_set();
+ BarrierSet *bs = BarrierSet::barrier_set();
bs->on_slowpath_allocation_exit(thread, new_obj);
}
--- a/src/hotspot/share/runtime/thread.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/thread.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -33,6 +33,7 @@
#include "code/scopeDesc.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compileTask.hpp"
+#include "gc/shared/barrierSet.hpp"
#include "gc/shared/gcId.hpp"
#include "gc/shared/gcLocker.inline.hpp"
#include "gc/shared/workgroup.hpp"
@@ -105,7 +106,9 @@
#include "services/threadService.hpp"
#include "trace/traceMacros.hpp"
#include "trace/tracing.hpp"
+#include "trace/tracingExport.hpp"
#include "utilities/align.hpp"
+#include "utilities/copy.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
@@ -310,6 +313,15 @@
"bug in forced alignment of thread objects");
}
#endif // ASSERT
+
+ // Notify the barrier set that a thread is being created. Note that the
+ // main thread is created before a barrier set is available. The call to
+ // BarrierSet::on_thread_create() for the main thread is therefore deferred
+ // until it calls BarrierSet::set_barrier_set().
+ BarrierSet* const barrier_set = BarrierSet::barrier_set();
+ if (barrier_set != NULL) {
+ barrier_set->on_thread_create(this);
+ }
}
void Thread::initialize_thread_current() {
@@ -360,6 +372,13 @@
Thread::~Thread() {
EVENT_THREAD_DESTRUCT(this);
+ // Notify the barrier set that a thread is being destroyed. Note that a barrier
+ // set might not be available if we encountered errors during bootstrapping.
+ BarrierSet* const barrier_set = BarrierSet::barrier_set();
+ if (barrier_set != NULL) {
+ barrier_set->on_thread_destroy(this);
+ }
+
// stack_base can be NULL if the thread is never started or exited before
// record_stack_base_and_size called. Although, we would like to ensure
// that all started threads do call record_stack_base_and_size(), there is
@@ -1588,18 +1607,8 @@
pd_initialize();
}
-#if INCLUDE_ALL_GCS
-SATBMarkQueueSet JavaThread::_satb_mark_queue_set;
-DirtyCardQueueSet JavaThread::_dirty_card_queue_set;
-#endif // INCLUDE_ALL_GCS
-
JavaThread::JavaThread(bool is_attaching_via_jni) :
- Thread()
-#if INCLUDE_ALL_GCS
- , _satb_mark_queue(&_satb_mark_queue_set),
- _dirty_card_queue(&_dirty_card_queue_set)
-#endif // INCLUDE_ALL_GCS
-{
+ Thread() {
initialize();
if (is_attaching_via_jni) {
_jni_attach_state = _attaching_via_jni;
@@ -1661,12 +1670,7 @@
static void sweeper_thread_entry(JavaThread* thread, TRAPS);
JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) :
- Thread()
-#if INCLUDE_ALL_GCS
- , _satb_mark_queue(&_satb_mark_queue_set),
- _dirty_card_queue(&_dirty_card_queue_set)
-#endif // INCLUDE_ALL_GCS
-{
+ Thread() {
initialize();
_jni_attach_state = _not_attaching_via_jni;
set_entry_point(entry_point);
@@ -3432,17 +3436,14 @@
// All JavaThreads
#define ALL_JAVA_THREADS(X) DO_JAVA_THREADS(ThreadsSMRSupport::get_java_thread_list(), X)
-// All JavaThreads + all non-JavaThreads (i.e., every thread in the system)
-void Threads::threads_do(ThreadClosure* tc) {
- assert_locked_or_safepoint(Threads_lock);
- // ALL_JAVA_THREADS iterates through all JavaThreads
- ALL_JAVA_THREADS(p) {
- tc->do_thread(p);
- }
+// All non-JavaThreads (i.e., every non-JavaThread in the system).
+void Threads::non_java_threads_do(ThreadClosure* tc) {
// Someday we could have a table or list of all non-JavaThreads.
// For now, just manually iterate through them.
tc->do_thread(VMThread::vm_thread());
- Universe::heap()->gc_threads_do(tc);
+ if (Universe::heap() != NULL) {
+ Universe::heap()->gc_threads_do(tc);
+ }
WatcherThread *wt = WatcherThread::watcher_thread();
// Strictly speaking, the following NULL check isn't sufficient to make sure
// the data for WatcherThread is still valid upon being examined. However,
@@ -3455,9 +3456,26 @@
tc->do_thread(wt);
}
+#if INCLUDE_TRACE
+ Thread* sampler_thread = TracingExport::sampler_thread_acquire();
+ if (sampler_thread != NULL) {
+ tc->do_thread(sampler_thread);
+ }
+#endif
+
// If CompilerThreads ever become non-JavaThreads, add them here
}
+// All JavaThreads + all non-JavaThreads (i.e., every thread in the system).
+void Threads::threads_do(ThreadClosure* tc) {
+ assert_locked_or_safepoint(Threads_lock);
+ // ALL_JAVA_THREADS iterates through all JavaThreads.
+ ALL_JAVA_THREADS(p) {
+ tc->do_thread(p);
+ }
+ non_java_threads_do(tc);
+}
+
void Threads::possibly_parallel_threads_do(bool is_par, ThreadClosure* tc) {
int cp = Threads::thread_claim_parity();
ALL_JAVA_THREADS(p) {
@@ -3891,6 +3909,13 @@
// cache the system and platform class loaders
SystemDictionary::compute_java_loaders(CHECK_JNI_ERR);
+#if INCLUDE_CDS
+ if (DumpSharedSpaces) {
+ // capture the module path info from the ModuleEntryTable
+ ClassLoader::initialize_module_path(THREAD);
+ }
+#endif
+
#if INCLUDE_JVMCI
if (force_JVMCI_intialization) {
JVMCIRuntime::force_initialization(CHECK_JNI_ERR);
--- a/src/hotspot/share/runtime/thread.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/thread.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -26,6 +26,7 @@
#define SHARE_VM_RUNTIME_THREAD_HPP
#include "jni.h"
+#include "gc/shared/gcThreadLocalData.hpp"
#include "gc/shared/threadLocalAllocBuffer.hpp"
#include "memory/allocation.hpp"
#include "oops/oop.hpp"
@@ -47,10 +48,6 @@
#include "utilities/align.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/dirtyCardQueue.hpp"
-#include "gc/g1/satbMarkQueue.hpp"
-#endif // INCLUDE_ALL_GCS
#ifdef ZERO
# include "stack_zero.hpp"
#endif
@@ -112,6 +109,22 @@
static THREAD_LOCAL_DECL Thread* _thr_current;
#endif
+ private:
+ // Thread local data area available to the GC. The internal
+ // structure and contents of this data area is GC-specific.
+ // Only GC and GC barrier code should access this data area.
+ GCThreadLocalData _gc_data;
+
+ public:
+ static ByteSize gc_data_offset() {
+ return byte_offset_of(Thread, _gc_data);
+ }
+
+ template <typename T> T* gc_data() {
+ STATIC_ASSERT(sizeof(T) <= sizeof(_gc_data));
+ return reinterpret_cast<T*>(&_gc_data);
+ }
+
// Exception handling
// (Note: _pending_exception and friends are in ThreadShadow)
//oop _pending_exception; // pending exception for current thread
@@ -1059,18 +1072,6 @@
} _jmp_ring[jump_ring_buffer_size];
#endif // PRODUCT
-#if INCLUDE_ALL_GCS
- // Support for G1 barriers
-
- SATBMarkQueue _satb_mark_queue; // Thread-local log for SATB barrier.
- // Set of all such queues.
- static SATBMarkQueueSet _satb_mark_queue_set;
-
- DirtyCardQueue _dirty_card_queue; // Thread-local log for dirty cards.
- // Set of all such queues.
- static DirtyCardQueueSet _dirty_card_queue_set;
-#endif // INCLUDE_ALL_GCS
-
friend class VMThread;
friend class ThreadWaitTransition;
friend class VM_Exit;
@@ -1670,11 +1671,6 @@
return byte_offset_of(JavaThread, _should_post_on_exceptions_flag);
}
-#if INCLUDE_ALL_GCS
- static ByteSize satb_mark_queue_offset() { return byte_offset_of(JavaThread, _satb_mark_queue); }
- static ByteSize dirty_card_queue_offset() { return byte_offset_of(JavaThread, _dirty_card_queue); }
-#endif // INCLUDE_ALL_GCS
-
// Returns the jni environment for this thread
JNIEnv* jni_environment() { return &_jni_environment; }
@@ -1945,20 +1941,6 @@
_stack_size_at_create = value;
}
-#if INCLUDE_ALL_GCS
- // SATB marking queue support
- SATBMarkQueue& satb_mark_queue() { return _satb_mark_queue; }
- static SATBMarkQueueSet& satb_mark_queue_set() {
- return _satb_mark_queue_set;
- }
-
- // Dirty card queue support
- DirtyCardQueue& dirty_card_queue() { return _dirty_card_queue; }
- static DirtyCardQueueSet& dirty_card_queue_set() {
- return _dirty_card_queue_set;
- }
-#endif // INCLUDE_ALL_GCS
-
// Machine dependent stuff
#include OS_CPU_HEADER(thread)
@@ -2114,6 +2096,7 @@
// thread to the thread list before allocating its thread object
static void add(JavaThread* p, bool force_daemon = false);
static void remove(JavaThread* p);
+ static void non_java_threads_do(ThreadClosure* tc);
static void threads_do(ThreadClosure* tc);
static void possibly_parallel_threads_do(bool is_par, ThreadClosure* tc);
--- a/src/hotspot/share/runtime/threadSMR.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/threadSMR.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -470,16 +470,6 @@
ThreadsListHandle::ThreadsListHandle(Thread *self) : _list(ThreadsSMRSupport::acquire_stable_list(self, /* is_ThreadsListSetter */ false)), _self(self) {
assert(self == Thread::current(), "sanity check");
- // Threads::threads_do() is used by the Thread-SMR protocol to visit all
- // Threads in the system which ensures the safety of the ThreadsList
- // managed by this ThreadsListHandle, but JavaThreads that are not on
- // the Threads list cannot be included in that visit. The JavaThread that
- // calls Threads::destroy_vm() is exempt from this check because it has
- // to logically exit as part of the shutdown procedure. This is safe
- // because VM_Exit::_shutdown_thread is not set until after the VMThread
- // has started the final safepoint which holds the Threads_lock for the
- // remainder of the VM's life.
- assert(!self->is_Java_thread() || self == VM_Exit::shutdown_thread() || (((JavaThread*)self)->on_thread_list() && !((JavaThread*)self)->is_terminated()), "JavaThread must be on the Threads list to use a ThreadsListHandle");
if (EnableThreadSMRStatistics) {
_timer.start();
}
@@ -553,6 +543,76 @@
}
}
+// Closure to determine if the specified JavaThread is found by
+// threads_do().
+//
+class VerifyHazardPointerThreadClosure : public ThreadClosure {
+ private:
+ bool _found;
+ Thread *_self;
+
+ public:
+ VerifyHazardPointerThreadClosure(Thread *self) : _found(false), _self(self) {}
+
+ bool found() const { return _found; }
+
+ virtual void do_thread(Thread *thread) {
+ if (thread == _self) {
+ _found = true;
+ }
+ }
+};
+
+// Apply the closure to all threads in the system, with a snapshot of
+// all JavaThreads provided by the list parameter.
+void ThreadsSMRSupport::threads_do(ThreadClosure *tc, ThreadsList *list) {
+ list->threads_do(tc);
+ Threads::non_java_threads_do(tc);
+}
+
+// Apply the closure to all threads in the system.
+void ThreadsSMRSupport::threads_do(ThreadClosure *tc) {
+ threads_do(tc, _java_thread_list);
+}
+
+// Verify that the stable hazard pointer used to safely keep threads
+// alive is scanned by threads_do() which is a key piece of honoring
+// the Thread-SMR protocol.
+void ThreadsSMRSupport::verify_hazard_pointer_scanned(Thread *self, ThreadsList *threads) {
+#ifdef ASSERT
+ assert(threads != NULL, "threads must not be NULL");
+
+ // The closure will attempt to verify that the calling thread can
+ // be found by threads_do() on the specified ThreadsList. If it
+ // is successful, then the specified ThreadsList was acquired as
+ // a stable hazard pointer by the calling thread in a way that
+ // honored the Thread-SMR protocol.
+ //
+ // If the calling thread cannot be found by threads_do() and if
+ // it is not the shutdown thread, then the calling thread is not
+ // honoring the Thread-SMR ptotocol. This means that the specified
+ // ThreadsList is not a stable hazard pointer and can be freed
+ // by another thread from the to-be-deleted list at any time.
+ //
+ // Note: The shutdown thread has removed itself from the Threads
+ // list and is safe to have a waiver from this check because
+ // VM_Exit::_shutdown_thread is not set until after the VMThread
+ // has started the final safepoint which holds the Threads_lock
+ // for the remainder of the VM's life.
+ //
+ VerifyHazardPointerThreadClosure cl(self);
+ threads_do(&cl, threads);
+
+ // If the calling thread is not honoring the Thread-SMR protocol,
+ // then we will either crash in threads_do() above because 'threads'
+ // was freed by another thread or we will fail the assert() below.
+ // In either case, we won't get past this point with a badly placed
+ // ThreadsListHandle.
+
+ assert(cl.found() || self == VM_Exit::shutdown_thread(), "Acquired a ThreadsList snapshot from a thread not recognized by the Thread-SMR protocol.");
+#endif
+}
+
void ThreadsListSetter::set() {
assert(_target->get_threads_hazard_ptr() == NULL, "hazard ptr should not already be set");
(void) ThreadsSMRSupport::acquire_stable_list(_target, /* is_ThreadsListSetter */ true);
@@ -626,6 +686,8 @@
// are protected and hence they should not be deleted until everyone
// agrees it is safe to do so.
+ verify_hazard_pointer_scanned(self, threads);
+
return threads;
}
@@ -662,6 +724,8 @@
}
log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::acquire_stable_list: add NestedThreadsList node containing ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(node->t_list()));
+ verify_hazard_pointer_scanned(self, node->t_list());
+
return node->t_list();
}
@@ -722,7 +786,7 @@
// Gather a hash table of the current hazard ptrs:
ThreadScanHashtable *scan_table = new ThreadScanHashtable(hash_table_size);
ScanHazardPtrGatherThreadsListClosure scan_cl(scan_table);
- Threads::threads_do(&scan_cl);
+ threads_do(&scan_cl);
// Walk through the linked list of pending freeable ThreadsLists
// and free the ones that are not referenced from hazard ptrs.
@@ -784,7 +848,7 @@
// hazard ptrs.
ThreadScanHashtable *scan_table = new ThreadScanHashtable(hash_table_size);
ScanHazardPtrGatherProtectedThreadsClosure scan_cl(scan_table);
- Threads::threads_do(&scan_cl);
+ threads_do(&scan_cl);
bool thread_is_protected = false;
if (scan_table->has_entry((void*)thread)) {
@@ -949,7 +1013,7 @@
log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::smr_delete: thread=" INTPTR_FORMAT " is not deleted.", os::current_thread_id(), p2i(thread));
if (log_is_enabled(Debug, os, thread)) {
ScanHazardPtrPrintMatchingThreadsClosure scan_cl(thread);
- Threads::threads_do(&scan_cl);
+ threads_do(&scan_cl);
}
}
} // We have to drop the Threads_lock to wait or delete the thread
--- a/src/hotspot/share/runtime/threadSMR.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/threadSMR.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,6 +28,8 @@
#include "memory/allocation.hpp"
#include "runtime/timer.hpp"
+class ThreadClosure;
+
// Thread Safe Memory Reclamation (Thread-SMR) support.
//
// ThreadsListHandles are used to safely perform operations on one or more
@@ -124,9 +126,12 @@
static void release_stable_list_nested_path(Thread *self);
static void release_stable_list_wake_up(char *log_str);
static void set_delete_notify();
+ static void threads_do(ThreadClosure *tc);
+ static void threads_do(ThreadClosure *tc, ThreadsList *list);
static void update_deleted_thread_time_max(uint new_value);
static void update_java_thread_list_max(uint new_value);
static void update_tlh_time_max(uint new_value);
+ static void verify_hazard_pointer_scanned(Thread *self, ThreadsList *threads);
static ThreadsList* xchg_java_thread_list(ThreadsList* new_list);
public:
--- a/src/hotspot/share/runtime/vmStructs.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/runtime/vmStructs.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -44,19 +44,7 @@
#include "code/vmreg.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/oopMap.hpp"
-#include "gc/parallel/immutableSpace.hpp"
-#include "gc/parallel/mutableSpace.hpp"
-#include "gc/serial/defNewGeneration.hpp"
-#include "gc/serial/serialHeap.hpp"
-#include "gc/serial/tenuredGeneration.hpp"
-#include "gc/cms/cmsHeap.hpp"
-#include "gc/shared/cardTableRS.hpp"
-#include "gc/shared/collectedHeap.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
-#include "gc/shared/generation.hpp"
-#include "gc/shared/generationSpec.hpp"
-#include "gc/shared/oopStorage.hpp"
-#include "gc/shared/space.hpp"
+#include "gc/shared/vmStructs_gc.hpp"
#include "interpreter/bytecodeInterpreter.hpp"
#include "interpreter/bytecodes.hpp"
#include "interpreter/interpreter.hpp"
@@ -113,23 +101,6 @@
#include OS_HEADER(vmStructs)
#include OS_CPU_HEADER(vmStructs)
-#if INCLUDE_ALL_GCS
-#include "gc/cms/compactibleFreeListSpace.hpp"
-#include "gc/cms/concurrentMarkSweepGeneration.hpp"
-#include "gc/cms/concurrentMarkSweepThread.hpp"
-#include "gc/cms/parNewGeneration.hpp"
-#include "gc/cms/vmStructs_cms.hpp"
-#include "gc/cms/vmStructs_parNew.hpp"
-#include "gc/g1/vmStructs_g1.hpp"
-#include "gc/parallel/asPSOldGen.hpp"
-#include "gc/parallel/asPSYoungGen.hpp"
-#include "gc/parallel/parallelScavengeHeap.hpp"
-#include "gc/parallel/psOldGen.hpp"
-#include "gc/parallel/psVirtualspace.hpp"
-#include "gc/parallel/psYoungGen.hpp"
-#include "gc/parallel/vmStructs_parallelgc.hpp"
-#endif // INCLUDE_ALL_GCS
-
#if INCLUDE_JVMCI
# include "jvmci/vmStructs_jvmci.hpp"
#endif
@@ -210,29 +181,38 @@
// NOTE that there are platform-specific additions to this table in
// vmStructs_<os>_<cpu>.hpp.
-#define VM_STRUCTS(nonstatic_field, \
- static_field, \
- static_ptr_volatile_field, \
- unchecked_nonstatic_field, \
- volatile_nonstatic_field, \
- nonproduct_nonstatic_field, \
- c1_nonstatic_field, \
- c2_nonstatic_field, \
- unchecked_c1_static_field, \
- unchecked_c2_static_field) \
+#define VM_STRUCTS(nonstatic_field, \
+ static_field, \
+ static_ptr_volatile_field, \
+ unchecked_nonstatic_field, \
+ volatile_nonstatic_field, \
+ nonproduct_nonstatic_field, \
+ c1_nonstatic_field, \
+ c2_nonstatic_field, \
+ unchecked_c1_static_field, \
+ unchecked_c2_static_field) \
+ \
+ /*************/ \
+ /* GC fields */ \
+ /*************/ \
+ \
+ VM_STRUCTS_GC(nonstatic_field, \
+ volatile_nonstatic_field, \
+ static_field, \
+ unchecked_nonstatic_field) \
\
/******************************************************************/ \
- /* OopDesc and Klass hierarchies (NOTE: MethodData* incomplete) */ \
+ /* OopDesc and Klass hierarchies (NOTE: MethodData* incomplete) */ \
/******************************************************************/ \
\
volatile_nonstatic_field(oopDesc, _mark, markOop) \
volatile_nonstatic_field(oopDesc, _metadata._klass, Klass*) \
volatile_nonstatic_field(oopDesc, _metadata._compressed_klass, narrowKlass) \
- static_field(BarrierSet, _bs, BarrierSet*) \
+ static_field(BarrierSet, _barrier_set, BarrierSet*) \
nonstatic_field(ArrayKlass, _dimension, int) \
volatile_nonstatic_field(ArrayKlass, _higher_dimension, Klass*) \
volatile_nonstatic_field(ArrayKlass, _lower_dimension, Klass*) \
- nonstatic_field(CompiledICHolder, _holder_metadata, Metadata*) \
+ nonstatic_field(CompiledICHolder, _holder_metadata, Metadata*) \
nonstatic_field(CompiledICHolder, _holder_klass, Klass*) \
nonstatic_field(ConstantPool, _tags, Array<u1>*) \
nonstatic_field(ConstantPool, _cache, ConstantPoolCache*) \
@@ -433,99 +413,9 @@
\
static_field(os, _polling_page, address) \
\
- /**********************************************************************************/ \
- /* Generation and Space hierarchies */ \
- /**********************************************************************************/ \
- \
- unchecked_nonstatic_field(AgeTable, sizes, sizeof(AgeTable::sizes)) \
- \
- nonstatic_field(BarrierSet, _fake_rtti, BarrierSet::FakeRtti) \
- \
- nonstatic_field(BarrierSet::FakeRtti, _concrete_tag, BarrierSet::Name) \
- \
- nonstatic_field(BlockOffsetTable, _bottom, HeapWord*) \
- nonstatic_field(BlockOffsetTable, _end, HeapWord*) \
- \
- nonstatic_field(BlockOffsetSharedArray, _reserved, MemRegion) \
- nonstatic_field(BlockOffsetSharedArray, _end, HeapWord*) \
- nonstatic_field(BlockOffsetSharedArray, _vs, VirtualSpace) \
- nonstatic_field(BlockOffsetSharedArray, _offset_array, u_char*) \
- \
- nonstatic_field(BlockOffsetArray, _array, BlockOffsetSharedArray*) \
- nonstatic_field(BlockOffsetArray, _sp, Space*) \
- nonstatic_field(BlockOffsetArrayContigSpace, _next_offset_threshold, HeapWord*) \
- nonstatic_field(BlockOffsetArrayContigSpace, _next_offset_index, size_t) \
- \
- nonstatic_field(BlockOffsetArrayNonContigSpace, _unallocated_block, HeapWord*) \
- \
- nonstatic_field(CardGeneration, _rs, CardTableRS*) \
- nonstatic_field(CardGeneration, _bts, BlockOffsetSharedArray*) \
- nonstatic_field(CardGeneration, _shrink_factor, size_t) \
- nonstatic_field(CardGeneration, _capacity_at_prologue, size_t) \
- nonstatic_field(CardGeneration, _used_at_prologue, size_t) \
- \
- nonstatic_field(CardTable, _whole_heap, const MemRegion) \
- nonstatic_field(CardTable, _guard_index, const size_t) \
- nonstatic_field(CardTable, _last_valid_index, const size_t) \
- nonstatic_field(CardTable, _page_size, const size_t) \
- nonstatic_field(CardTable, _byte_map_size, const size_t) \
- nonstatic_field(CardTable, _byte_map, jbyte*) \
- nonstatic_field(CardTable, _cur_covered_regions, int) \
- nonstatic_field(CardTable, _covered, MemRegion*) \
- nonstatic_field(CardTable, _committed, MemRegion*) \
- nonstatic_field(CardTable, _guard_region, MemRegion) \
- nonstatic_field(CardTable, _byte_map_base, jbyte*) \
- nonstatic_field(CardTableBarrierSet, _defer_initial_card_mark, bool) \
- nonstatic_field(CardTableBarrierSet, _card_table, CardTable*) \
- \
- nonstatic_field(CollectedHeap, _reserved, MemRegion) \
- nonstatic_field(CollectedHeap, _barrier_set, BarrierSet*) \
- nonstatic_field(CollectedHeap, _is_gc_active, bool) \
- nonstatic_field(CollectedHeap, _total_collections, unsigned int) \
- \
- nonstatic_field(CompactibleSpace, _compaction_top, HeapWord*) \
- nonstatic_field(CompactibleSpace, _first_dead, HeapWord*) \
- nonstatic_field(CompactibleSpace, _end_of_live, HeapWord*) \
- \
- nonstatic_field(ContiguousSpace, _top, HeapWord*) \
- nonstatic_field(ContiguousSpace, _concurrent_iteration_safe_limit, HeapWord*) \
- nonstatic_field(ContiguousSpace, _saved_mark_word, HeapWord*) \
- \
- nonstatic_field(DefNewGeneration, _old_gen, Generation*) \
- nonstatic_field(DefNewGeneration, _tenuring_threshold, uint) \
- nonstatic_field(DefNewGeneration, _age_table, AgeTable) \
- nonstatic_field(DefNewGeneration, _eden_space, ContiguousSpace*) \
- nonstatic_field(DefNewGeneration, _from_space, ContiguousSpace*) \
- nonstatic_field(DefNewGeneration, _to_space, ContiguousSpace*) \
- \
- nonstatic_field(Generation, _reserved, MemRegion) \
- nonstatic_field(Generation, _virtual_space, VirtualSpace) \
- nonstatic_field(Generation, _stat_record, Generation::StatRecord) \
- \
- nonstatic_field(Generation::StatRecord, invocations, int) \
- nonstatic_field(Generation::StatRecord, accumulated_time, elapsedTimer) \
- \
- nonstatic_field(GenerationSpec, _name, Generation::Name) \
- nonstatic_field(GenerationSpec, _init_size, size_t) \
- nonstatic_field(GenerationSpec, _max_size, size_t) \
- \
- nonstatic_field(GenCollectedHeap, _young_gen, Generation*) \
- nonstatic_field(GenCollectedHeap, _old_gen, Generation*) \
- nonstatic_field(GenCollectedHeap, _young_gen_spec, GenerationSpec*) \
- nonstatic_field(GenCollectedHeap, _old_gen_spec, GenerationSpec*) \
- \
- nonstatic_field(HeapWord, i, char*) \
- \
- nonstatic_field(MemRegion, _start, HeapWord*) \
- nonstatic_field(MemRegion, _word_size, size_t) \
- \
- nonstatic_field(OffsetTableContigSpace, _offsets, BlockOffsetArray) \
- \
- nonstatic_field(TenuredGeneration, _min_heap_delta_bytes, size_t) \
- nonstatic_field(TenuredGeneration, _the_space, ContiguousSpace*) \
- \
- nonstatic_field(Space, _bottom, HeapWord*) \
- nonstatic_field(Space, _end, HeapWord*) \
+ /**********/ \
+ /* Memory */ \
+ /**********/ \
\
nonstatic_field(ThreadLocalAllocBuffer, _start, HeapWord*) \
nonstatic_field(ThreadLocalAllocBuffer, _top, HeapWord*) \
@@ -910,8 +800,6 @@
nonstatic_field(JavaThread, _stack_size, size_t) \
nonstatic_field(JavaThread, _vframe_array_head, vframeArray*) \
nonstatic_field(JavaThread, _vframe_array_last, vframeArray*) \
- nonstatic_field(JavaThread, _satb_mark_queue, SATBMarkQueue) \
- nonstatic_field(JavaThread, _dirty_card_queue, DirtyCardQueue) \
volatile_nonstatic_field(JavaThread, _terminated, JavaThread::TerminatedTypes) \
nonstatic_field(Thread, _resource_area, ResourceArea*) \
nonstatic_field(CompilerThread, _env, ciEnv*) \
@@ -1260,13 +1148,7 @@
nonstatic_field(AccessFlags, _flags, jint) \
nonstatic_field(elapsedTimer, _counter, jlong) \
nonstatic_field(elapsedTimer, _active, bool) \
- nonstatic_field(InvocationCounter, _counter, unsigned int) \
- volatile_nonstatic_field(FreeChunk, _size, size_t) \
- nonstatic_field(FreeChunk, _next, FreeChunk*) \
- nonstatic_field(FreeChunk, _prev, FreeChunk*) \
- nonstatic_field(AdaptiveFreeList<FreeChunk>, _size, size_t) \
- nonstatic_field(AdaptiveFreeList<FreeChunk>, _count, ssize_t)
-
+ nonstatic_field(InvocationCounter, _counter, unsigned int)
//--------------------------------------------------------------------------------
// VM_TYPES
@@ -1453,73 +1335,6 @@
declare_toplevel_type(ClassLoaderData) \
declare_toplevel_type(ClassLoaderDataGraph) \
\
- /******************************************/ \
- /* Generation and space hierarchies */ \
- /* (needed for run-time type information) */ \
- /******************************************/ \
- \
- declare_toplevel_type(CollectedHeap) \
- declare_type(GenCollectedHeap, CollectedHeap) \
- declare_type(CMSHeap, GenCollectedHeap) \
- declare_type(SerialHeap, GenCollectedHeap) \
- declare_toplevel_type(Generation) \
- declare_type(DefNewGeneration, Generation) \
- declare_type(CardGeneration, Generation) \
- declare_type(TenuredGeneration, CardGeneration) \
- declare_toplevel_type(Space) \
- declare_type(CompactibleSpace, Space) \
- declare_type(ContiguousSpace, CompactibleSpace) \
- declare_type(OffsetTableContigSpace, ContiguousSpace) \
- declare_type(TenuredSpace, OffsetTableContigSpace) \
- declare_toplevel_type(BarrierSet) \
- declare_type(ModRefBarrierSet, BarrierSet) \
- declare_type(CardTableBarrierSet, ModRefBarrierSet) \
- declare_toplevel_type(CardTable) \
- declare_type(CardTableRS, CardTable) \
- declare_toplevel_type(BarrierSet::Name) \
- declare_toplevel_type(BlockOffsetSharedArray) \
- declare_toplevel_type(BlockOffsetTable) \
- declare_type(BlockOffsetArray, BlockOffsetTable) \
- declare_type(BlockOffsetArrayContigSpace, BlockOffsetArray) \
- declare_type(BlockOffsetArrayNonContigSpace, BlockOffsetArray) \
- \
- /* Miscellaneous other GC types */ \
- \
- declare_toplevel_type(AgeTable) \
- declare_toplevel_type(Generation::StatRecord) \
- declare_toplevel_type(GenerationSpec) \
- declare_toplevel_type(HeapWord) \
- declare_toplevel_type(MemRegion) \
- declare_toplevel_type(ThreadLocalAllocBuffer) \
- declare_toplevel_type(VirtualSpace) \
- declare_toplevel_type(SATBMarkQueue) \
- declare_toplevel_type(DirtyCardQueue) \
- \
- /* Pointers to Garbage Collection types */ \
- \
- declare_toplevel_type(BarrierSet*) \
- declare_toplevel_type(BlockOffsetSharedArray*) \
- declare_toplevel_type(CardTable*) \
- declare_toplevel_type(CardTable*const) \
- declare_toplevel_type(CardTableRS*) \
- declare_toplevel_type(CardTableBarrierSet*) \
- declare_toplevel_type(CardTableBarrierSet**) \
- declare_toplevel_type(CollectedHeap*) \
- declare_toplevel_type(ContiguousSpace*) \
- declare_toplevel_type(DefNewGeneration*) \
- declare_toplevel_type(GenCollectedHeap*) \
- declare_toplevel_type(Generation*) \
- declare_toplevel_type(GenerationSpec**) \
- declare_toplevel_type(HeapWord*) \
- declare_toplevel_type(HeapWord* volatile) \
- declare_toplevel_type(MemRegion*) \
- declare_toplevel_type(OffsetTableContigSpace*) \
- declare_toplevel_type(Space*) \
- declare_toplevel_type(TenuredGeneration*) \
- declare_toplevel_type(ThreadLocalAllocBuffer*) \
- \
- declare_toplevel_type(BarrierSet::FakeRtti) \
- \
/************************/ \
/* PerfMemory - jvmstat */ \
/************************/ \
@@ -2183,15 +1998,13 @@
declare_toplevel_type(Annotations*) \
declare_type(OopMapValue, StackObj) \
\
- /***************/ \
- /* Miscellaneous types */ \
- /***************/ \
+ /************/ \
+ /* GC types */ \
+ /************/ \
\
- /* freelist */ \
- declare_toplevel_type(FreeChunk*) \
- declare_toplevel_type(AdaptiveFreeList<FreeChunk>*) \
- declare_toplevel_type(AdaptiveFreeList<FreeChunk>)
-
+ VM_TYPES_GC(declare_type, \
+ declare_toplevel_type, \
+ declare_integer_type)
//--------------------------------------------------------------------------------
// VM_INT_CONSTANTS
@@ -2202,11 +2015,19 @@
// all #defined constants.
#define VM_INT_CONSTANTS(declare_constant, \
+ declare_constant_with_value, \
declare_preprocessor_constant, \
declare_c1_constant, \
declare_c2_constant, \
declare_c2_preprocessor_constant) \
\
+ /****************/ \
+ /* GC constants */ \
+ /****************/ \
+ \
+ VM_INT_CONSTANTS_GC(declare_constant, \
+ declare_constant_with_value) \
+ \
/******************/ \
/* Useful globals */ \
/******************/ \
@@ -2230,51 +2051,6 @@
\
declare_constant(LogKlassAlignmentInBytes) \
\
- /********************************************/ \
- /* Generation and Space Hierarchy Constants */ \
- /********************************************/ \
- \
- declare_constant(AgeTable::table_size) \
- \
- declare_constant(BarrierSet::ModRef) \
- declare_constant(BarrierSet::CardTableBarrierSet) \
- declare_constant(BarrierSet::G1BarrierSet) \
- \
- declare_constant(BOTConstants::LogN) \
- declare_constant(BOTConstants::LogN_words) \
- declare_constant(BOTConstants::N_bytes) \
- declare_constant(BOTConstants::N_words) \
- declare_constant(BOTConstants::LogBase) \
- declare_constant(BOTConstants::Base) \
- declare_constant(BOTConstants::N_powers) \
- \
- declare_constant(CardTable::clean_card) \
- declare_constant(CardTable::last_card) \
- declare_constant(CardTable::dirty_card) \
- declare_constant(CardTable::Precise) \
- declare_constant(CardTable::ObjHeadPreciseArray) \
- declare_constant(CardTable::card_shift) \
- declare_constant(CardTable::card_size) \
- declare_constant(CardTable::card_size_in_words) \
- \
- declare_constant(CardTableRS::youngergen_card) \
- \
- declare_constant(G1CardTable::g1_young_gen) \
- \
- declare_constant(CollectedHeap::Serial) \
- declare_constant(CollectedHeap::Parallel) \
- declare_constant(CollectedHeap::CMS) \
- declare_constant(CollectedHeap::G1) \
- \
- /* constants from Generation::Name enum */ \
- \
- declare_constant(Generation::DefNew) \
- declare_constant(Generation::MarkSweepCompact) \
- declare_constant(Generation::Other) \
- \
- declare_constant(Generation::LogOfGenGrain) \
- declare_constant(Generation::GenGrain) \
- \
declare_constant(HeapWordSize) \
declare_constant(LogHeapWordSize) \
\
@@ -3012,19 +2788,6 @@
GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY,
GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY)
-#if INCLUDE_ALL_GCS
- VM_STRUCTS_PARALLELGC(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
- GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
- GENERATE_STATIC_VM_STRUCT_ENTRY)
-
- VM_STRUCTS_CMS(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
- GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
- GENERATE_STATIC_VM_STRUCT_ENTRY)
-
- VM_STRUCTS_G1(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
- GENERATE_STATIC_VM_STRUCT_ENTRY)
-#endif // INCLUDE_ALL_GCS
-
#if INCLUDE_TRACE
VM_STRUCTS_TRACE(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
GENERATE_STATIC_VM_STRUCT_ENTRY)
@@ -3075,20 +2838,6 @@
GENERATE_C2_VM_TYPE_ENTRY,
GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY)
-#if INCLUDE_ALL_GCS
- VM_TYPES_PARALLELGC(GENERATE_VM_TYPE_ENTRY,
- GENERATE_TOPLEVEL_VM_TYPE_ENTRY)
-
- VM_TYPES_CMS(GENERATE_VM_TYPE_ENTRY,
- GENERATE_TOPLEVEL_VM_TYPE_ENTRY)
-
- VM_TYPES_PARNEW(GENERATE_VM_TYPE_ENTRY)
-
- VM_TYPES_G1(GENERATE_VM_TYPE_ENTRY,
- GENERATE_TOPLEVEL_VM_TYPE_ENTRY,
- GENERATE_INTEGER_VM_TYPE_ENTRY)
-#endif // INCLUDE_ALL_GCS
-
#if INCLUDE_TRACE
VM_TYPES_TRACE(GENERATE_VM_TYPE_ENTRY,
GENERATE_TOPLEVEL_VM_TYPE_ENTRY)
@@ -3131,20 +2880,12 @@
VMIntConstantEntry VMStructs::localHotSpotVMIntConstants[] = {
VM_INT_CONSTANTS(GENERATE_VM_INT_CONSTANT_ENTRY,
+ GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY,
GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY,
GENERATE_C1_VM_INT_CONSTANT_ENTRY,
GENERATE_C2_VM_INT_CONSTANT_ENTRY,
GENERATE_C2_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
-#if INCLUDE_ALL_GCS
- VM_INT_CONSTANTS_CMS(GENERATE_VM_INT_CONSTANT_ENTRY)
-
- VM_INT_CONSTANTS_PARNEW(GENERATE_VM_INT_CONSTANT_ENTRY)
-
- VM_INT_CONSTANTS_G1(GENERATE_VM_INT_CONSTANT_ENTRY,
- GENERATE_VM_INT_CONSTANT_WITH_VALUE_ENTRY)
-#endif // INCLUDE_ALL_GCS
-
#if INCLUDE_TRACE
VM_INT_CONSTANTS_TRACE(GENERATE_VM_INT_CONSTANT_ENTRY)
#endif
@@ -3222,20 +2963,6 @@
CHECK_NO_OP,
CHECK_NO_OP);
-#if INCLUDE_ALL_GCS
- VM_STRUCTS_PARALLELGC(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
- CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY,
- CHECK_STATIC_VM_STRUCT_ENTRY);
-
- VM_STRUCTS_CMS(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
- CHECK_VOLATILE_NONSTATIC_VM_STRUCT_ENTRY,
- CHECK_STATIC_VM_STRUCT_ENTRY);
-
- VM_STRUCTS_G1(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
- CHECK_STATIC_VM_STRUCT_ENTRY);
-
-#endif // INCLUDE_ALL_GCS
-
#if INCLUDE_TRACE
VM_STRUCTS_TRACE(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
CHECK_STATIC_VM_STRUCT_ENTRY);
@@ -3268,21 +2995,6 @@
CHECK_C2_VM_TYPE_ENTRY,
CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY);
-#if INCLUDE_ALL_GCS
- VM_TYPES_PARALLELGC(CHECK_VM_TYPE_ENTRY,
- CHECK_SINGLE_ARG_VM_TYPE_NO_OP);
-
- VM_TYPES_CMS(CHECK_VM_TYPE_ENTRY,
- CHECK_SINGLE_ARG_VM_TYPE_NO_OP);
-
- VM_TYPES_PARNEW(CHECK_VM_TYPE_ENTRY)
-
- VM_TYPES_G1(CHECK_VM_TYPE_ENTRY,
- CHECK_SINGLE_ARG_VM_TYPE_NO_OP,
- CHECK_SINGLE_ARG_VM_TYPE_NO_OP);
-
-#endif // INCLUDE_ALL_GCS
-
#if INCLUDE_TRACE
VM_TYPES_TRACE(CHECK_VM_TYPE_ENTRY,
CHECK_SINGLE_ARG_VM_TYPE_NO_OP);
@@ -3343,16 +3055,6 @@
ENSURE_C2_FIELD_TYPE_PRESENT,
CHECK_NO_OP,
CHECK_NO_OP));
-#if INCLUDE_ALL_GCS
- debug_only(VM_STRUCTS_PARALLELGC(ENSURE_FIELD_TYPE_PRESENT,
- ENSURE_FIELD_TYPE_PRESENT,
- ENSURE_FIELD_TYPE_PRESENT));
- debug_only(VM_STRUCTS_CMS(ENSURE_FIELD_TYPE_PRESENT,
- ENSURE_FIELD_TYPE_PRESENT,
- ENSURE_FIELD_TYPE_PRESENT));
- debug_only(VM_STRUCTS_G1(ENSURE_FIELD_TYPE_PRESENT,
- ENSURE_FIELD_TYPE_PRESENT));
-#endif // INCLUDE_ALL_GCS
#if INCLUDE_TRACE
debug_only(VM_STRUCTS_TRACE(ENSURE_FIELD_TYPE_PRESENT,
--- a/src/hotspot/share/services/attachListener.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/services/attachListener.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -334,7 +334,9 @@
static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
os::set_priority(thread, NearMaxPriority);
- thread->record_stack_base_and_size();
+ assert(thread == Thread::current(), "Must be");
+ assert(thread->stack_base() != NULL && thread->stack_size() > 0,
+ "Should already be setup");
if (AttachListener::pd_init() != 0) {
return;
--- a/src/hotspot/share/services/diagnosticCommand.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/services/diagnosticCommand.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -137,9 +137,15 @@
_dcmdparser.add_dcmd_argument(&_cmd);
};
+
+static int compare_strings(const char** s1, const char** s2) {
+ return ::strcmp(*s1, *s2);
+}
+
void HelpDCmd::execute(DCmdSource source, TRAPS) {
if (_all.value()) {
GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(source);
+ cmd_list->sort(compare_strings);
for (int i = 0; i < cmd_list->length(); i++) {
DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
strlen(cmd_list->at(i)));
@@ -180,6 +186,7 @@
} else {
output()->print_cr("The following commands are available:");
GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(source);
+ cmd_list->sort(compare_strings);
for (int i = 0; i < cmd_list->length(); i++) {
DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
strlen(cmd_list->at(i)));
--- a/src/hotspot/share/services/heapDumper.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/services/heapDumper.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -28,7 +28,6 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc/shared/gcLocker.hpp"
-#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
@@ -52,9 +51,6 @@
#include "services/threadService.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/parallel/parallelScavengeHeap.hpp"
-#endif // INCLUDE_ALL_GCS
/*
* HPROF binary format - description copied from:
--- a/src/hotspot/share/services/memTracker.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/services/memTracker.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -41,7 +41,7 @@
release
};
Tracker(enum TrackerType type) : _type(type) { }
- void record(address addr, size_t size);
+ void record(address addr, size_t size) { }
private:
enum TrackerType _type;
};
@@ -313,4 +313,3 @@
#endif // INCLUDE_NMT
#endif // SHARE_VM_SERVICES_MEM_TRACKER_HPP
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/trace/tracingExport.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 "runtime/orderAccess.inline.hpp"
+#include "trace/tracingExport.hpp"
+
+// Allow lock-free reads of _sampler_thread.
+Thread* volatile TracingExport::_sampler_thread = NULL;
+
+Thread* TracingExport::sampler_thread_acquire() {
+ return (Thread*)OrderAccess::load_acquire(&_sampler_thread);
+}
+
+void TracingExport::set_sampler_thread_with_lock(Thread* thread) {
+ // Grab Threads_lock to avoid conflicts with Thread-SMR scans.
+ MutexLocker ml(Threads_lock);
+ assert(thread == NULL || _sampler_thread == NULL, "_sampler_thread should not already be set.");
+ // To match with the lock-free load_acquire():
+ OrderAccess::release_store(&_sampler_thread, thread);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/trace/tracingExport.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_TRACE_TRACINGEXPORT_HPP
+#define SHARE_VM_TRACE_TRACINGEXPORT_HPP
+
+#include "runtime/thread.hpp"
+
+class TracingExport : AllStatic {
+ public:
+ static Thread* sampler_thread_acquire();
+ static void set_sampler_thread_with_lock(Thread* thread);
+
+ private:
+ static Thread* volatile _sampler_thread;
+};
+
+#endif // SHARE_VM_TRACE_TRACINGEXPORT_HPP
--- a/src/hotspot/share/utilities/macros.hpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/utilities/macros.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -109,11 +109,13 @@
#define CDS_ONLY(x) x
#define NOT_CDS(x)
#define NOT_CDS_RETURN /* next token must be ; */
+#define NOT_CDS_RETURN0 /* next token must be ; */
#define NOT_CDS_RETURN_(code) /* next token must be ; */
#else
#define CDS_ONLY(x)
#define NOT_CDS(x) x
-#define NOT_CDS_RETURN {}
+#define NOT_CDS_RETURN {}
+#define NOT_CDS_RETURN0 { return 0; }
#define NOT_CDS_RETURN_(code) { return code; }
#endif // INCLUDE_CDS
@@ -141,9 +143,11 @@
#endif // INCLUDE_ALL_GCS
#if INCLUDE_ALL_GCS
+#define ALL_GCS_ONLY(x) x
#define NOT_ALL_GCS_RETURN /* next token must be ; */
#define NOT_ALL_GCS_RETURN_(code) /* next token must be ; */
#else
+#define ALL_GCS_ONLY(x)
#define NOT_ALL_GCS_RETURN {}
#define NOT_ALL_GCS_RETURN_(code) { return code; }
#endif // INCLUDE_ALL_GCS
--- a/src/hotspot/share/utilities/nativeCallStack.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/utilities/nativeCallStack.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,6 +24,7 @@
#include "precompiled.hpp"
#include "runtime/os.hpp"
+#include "utilities/decoder.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/nativeCallStack.hpp"
@@ -37,15 +38,15 @@
// to call os::get_native_stack. A tail call is used if _NMT_NOINLINE_ is not defined
// (which means this is not a slowdebug build), and we are on 64-bit (except Windows).
// This is not necessarily a rule, but what has been obvserved to date.
-#define TAIL_CALL (!defined(_NMT_NOINLINE_) && !defined(WINDOWS) && defined(_LP64))
-#if !TAIL_CALL
+#if (defined(_NMT_NOINLINE_) || defined(_WINDOWS) || !defined(_LP64))
+ // Not a tail call.
toSkip++;
#if (defined(_NMT_NOINLINE_) && defined(BSD) && defined(_LP64))
// Mac OS X slowdebug builds have this odd behavior where NativeCallStack::NativeCallStack
// appears as two frames, so we need to skip an extra frame.
toSkip++;
-#endif
-#endif
+#endif // Special-case for BSD.
+#endif // Not a tail call.
os::get_native_stack(_stack, NMT_TrackingStackDepth, toSkip);
} else {
for (int index = 0; index < NMT_TrackingStackDepth; index ++) {
@@ -102,6 +103,7 @@
address pc;
char buf[1024];
int offset;
+ int line_no;
if (is_empty()) {
for (int index = 0; index < indent; index ++) out->print(" ");
out->print("[BOOTSTRAP]");
@@ -112,10 +114,15 @@
// Print indent
for (int index = 0; index < indent; index ++) out->print(" ");
if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) {
- out->print_cr("[" PTR_FORMAT "] %s+0x%x", p2i(pc), buf, offset);
+ out->print("[" PTR_FORMAT "] %s+0x%x", p2i(pc), buf, offset);
} else {
- out->print_cr("[" PTR_FORMAT "]", p2i(pc));
+ out->print("[" PTR_FORMAT "]", p2i(pc));
}
+
+ if (Decoder::get_source_info(pc, buf, sizeof(buf), &line_no)) {
+ out->print(" (%s:%d)", buf, line_no);
+ }
+ out->cr();
}
}
}
--- a/src/hotspot/share/utilities/ostream.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/utilities/ostream.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1027,6 +1027,8 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#elif defined(_WINDOWS)
+#include <winsock2.h>
#endif
// Network access
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/utilities/spinYield.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 "runtime/os.hpp"
+#include "utilities/ostream.hpp"
+#include "utilities/spinYield.hpp"
+#include "utilities/ticks.inline.hpp"
+
+SpinYield::SpinYield(uint spin_limit, uint yield_limit) :
+ _sleep_time(),
+ _spins(0),
+ _yields(0),
+ _spin_limit(os::is_MP() ? spin_limit : 0),
+ _yield_limit(yield_limit)
+{}
+
+void SpinYield::yield_or_sleep() {
+ if (_yields < _yield_limit) {
+ ++_yields;
+ os::naked_yield();
+ } else {
+ Ticks sleep_start = Ticks::now();
+ os::naked_short_sleep(1);
+ Ticks sleep_end = Ticks::now();
+ _sleep_time += (sleep_end - sleep_start);
+ }
+}
+
+static const char* print_separator(outputStream* s, const char* separator) {
+ s->print("%s", separator);
+ return ", ";
+}
+
+void SpinYield::report(outputStream* s) const {
+ const char* initial_separator = "";
+ const char* separator = initial_separator;
+ if (_spins > 0) { // Report spins, if any.
+ separator = print_separator(s, separator);
+ s->print("spins = %u", _spins);
+ }
+ if (_yields > 0) { // Report yields, if any.
+ separator = print_separator(s, separator);
+ s->print("yields = %u", _yields);
+ }
+ if (_sleep_time.value() != 0) { // Report sleep duration, if slept.
+ separator = print_separator(s, separator);
+ s->print("sleep = " JLONG_FORMAT " usecs",
+ TicksToTimeHelper::milliseconds(_sleep_time));
+ }
+ if (separator == initial_separator) {
+ s->print("no waiting");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/utilities/spinYield.hpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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_UTILITIES_SPINYIELD_HPP
+#define SHARE_UTILITIES_SPINYIELD_HPP
+
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/ticks.hpp"
+
+class outputStream;
+
+extern "C" int SpinPause();
+
+class SpinYield : public StackObj {
+ Tickspan _sleep_time;
+ uint _spins;
+ uint _yields;
+ uint _spin_limit;
+ uint _yield_limit;
+
+ void yield_or_sleep();
+
+public:
+ static const uint default_spin_limit = 4096;
+ static const uint default_yield_limit = 64;
+
+ // spin_limit is ignored (treated as zero) when !os::is_MP().
+ explicit SpinYield(uint spin_limit = default_spin_limit,
+ uint yield_limit = default_yield_limit);
+
+ // Perform next round of delay.
+ void wait() {
+ // Simple policy: return immediately (spinning) configured number
+ // of times, then switch to yield/sleep. Future work might
+ // provide other policies, such as (1) always spin if system is
+ // not saturated, or (2) sleeping if yielding is ineffective.
+ if (_spins < _spin_limit) {
+ ++_spins;
+ SpinPause();
+ } else {
+ yield_or_sleep();
+ }
+ }
+
+ // Write information about the wait duration to s.
+ void report(outputStream* s) const;
+};
+
+#endif // SHARE_UTILITIES_SPINYIELD_HPP
--- a/src/hotspot/share/utilities/vmError.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/src/hotspot/share/utilities/vmError.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1478,7 +1478,7 @@
out.print_raw ("/bin/sh -c ");
#elif defined(SOLARIS)
out.print_raw ("/usr/bin/sh -c ");
-#elif defined(WINDOWS)
+#elif defined(_WINDOWS)
out.print_raw ("cmd /C ");
#endif
out.print_raw ("\"");
--- a/src/java.base/share/classes/java/util/regex/Pattern.java Tue Apr 17 08:54:17 2018 -0700
+++ b/src/java.base/share/classes/java/util/regex/Pattern.java Tue Apr 17 18:18:53 2018 +0100
@@ -5821,15 +5821,35 @@
* }</pre>
*
* @return The predicate which can be used for finding a match on a
- * subsequence of a string
+ * subsequence of a string
* @since 1.8
- * @see Matcher#find
+ * @see Matcher#find
*/
public Predicate<String> asPredicate() {
return s -> matcher(s).find();
}
/**
+ * Creates a predicate that tests if this pattern matches a given input string.
+ *
+ * @apiNote
+ * This method creates a predicate that behaves as if it creates a matcher
+ * from the input sequence and then calls {@code matches}, for example a
+ * predicate of the form:
+ * <pre>{@code
+ * s -> matcher(s).matches();
+ * }</pre>
+ *
+ * @return The predicate which can be used for matching an input string
+ * against this pattern.
+ * @since 11
+ * @see Matcher#matches
+ */
+ public Predicate<String> asMatchPredicate() {
+ return s -> matcher(s).matches();
+ }
+
+ /**
* Creates a stream from the given input sequence around matches of this
* pattern.
*
--- a/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2015 SAP SE. All rights reserved.
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, SAP SE. All rights reserved.
* 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,6 @@
import java.io.IOException;
import java.io.File;
-// Based on linux/classes/sun/tools/attach/VirtualMachineImpl.java.
-
/*
* Aix implementation of HotSpotVirtualMachine
*/
@@ -140,7 +138,7 @@
* Execute the given command in the target VM.
*/
InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
- assert args.length <= 3; // includes null
+ assert args.length <= 3; // includes null
// did we detach?
synchronized (this) {
@@ -261,7 +259,7 @@
}
}
- // On Solaris/Linux/Aix a simple handshake is used to start the attach mechanism
+ // On Aix a simple handshake is used to start the attach mechanism
// if not already started. The client creates a .attach_pid<pid> file in the
// target VM's working directory (or temp directory), and the SIGQUIT handler
// checks for the file.
--- a/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.attach/aix/native/libattach/VirtualMachineImpl.c Tue Apr 17 18:18:53 2018 +0100
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2015 SAP SE. All rights reserved.
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, SAP SE. All rights reserved.
* 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,27 +24,18 @@
* questions.
*/
-#include "jni.h"
#include "jni_util.h"
-#include "jvm.h"
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
#include <unistd.h>
-#include <signal.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-
-/*
- * Based on 'LinuxVirtualMachine.c'. Non-relevant code has been removed and all
- * occurrences of the string "Linux" have been replaced by "Aix".
- */
#include "sun_tools_attach_VirtualMachineImpl.h"
@@ -67,15 +58,6 @@
if (fd == -1) {
JNU_ThrowIOExceptionWithLastError(env, "socket");
}
- /* added time out values */
- else {
- struct timeval tv;
- tv.tv_sec = 2 * 60;
- tv.tv_usec = 0;
-
- setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
- setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv));
- }
return (jint)fd;
}
@@ -125,23 +107,6 @@
}
}
-
-/*
- * Structure and callback function used to send a QUIT signal to all
- * children of a given process
- */
-typedef struct {
- pid_t ppid;
-} SendQuitContext;
-
-static void SendQuitCallback(const pid_t pid, void* user_data) {
- SendQuitContext* context = (SendQuitContext*)user_data;
- pid_t parent = getParent(pid);
- if (parent == context->ppid) {
- kill(pid, SIGQUIT);
- }
-}
-
/*
* Class: sun_tools_attach_VirtualMachineImpl
* Method: sendQuitTo
@@ -169,7 +134,7 @@
struct stat64 sb;
uid_t uid, gid;
int res;
- /* added missing initialization of the stat64 buffer */
+
memset(&sb, 0, sizeof(struct stat64));
/*
@@ -189,21 +154,21 @@
char msg[100];
jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE;
} else if (sb.st_gid != gid) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE;
} else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);
isError = JNI_TRUE;
}
if (isError) {
char buf[256];
- jio_snprintf(buf, sizeof(buf)-1, "well-known file %s is not secure: %s", p, msg);
+ snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg);
JNU_ThrowIOException(env, buf);
}
} else {
@@ -229,11 +194,7 @@
(JNIEnv *env, jclass cls, jint fd)
{
int res;
- /* Fixed deadlock when this call of close by the client is not seen by the attach server
- * which has accepted the (very short) connection already and is waiting for the request. But read don't get a byte,
- * because the close is lost without shutdown.
- */
- shutdown(fd, 2);
+ shutdown(fd, SHUT_RDWR);
RESTARTABLE(close(fd), res);
}
--- a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -105,7 +105,7 @@
} finally {
f.delete();
}
- }
+ }
// Check that the file owner/permission to avoid attaching to
// bogus process
@@ -274,7 +274,7 @@
return new File(root, ".java_pid" + ns_pid);
}
- // On Solaris/Linux a simple handshake is used to start the attach mechanism
+ // On Linux a simple handshake is used to start the attach mechanism
// if not already started. The client creates a .attach_pid<pid> file in the
// target VM's working directory (or temp directory), and the SIGQUIT handler
// checks for the file.
@@ -356,8 +356,6 @@
//-- native methods
- static native void sendQuitToChildrenOf(int pid) throws IOException;
-
static native void sendQuitTo(int pid) throws IOException;
static native void checkPermissions(String path) throws IOException;
--- a/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.attach/linux/native/libattach/VirtualMachineImpl.c Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,23 +23,18 @@
* questions.
*/
-#include "jni.h"
#include "jni_util.h"
-#include "jvm.h"
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
#include <unistd.h>
-#include <signal.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
#include "sun_tools_attach_VirtualMachineImpl.h"
@@ -55,85 +50,6 @@
DEF_STATIC_JNI_OnLoad
/*
- * Defines a callback that is invoked for each process
- */
-typedef void (*ProcessCallback)(const pid_t pid, void* user_data);
-
-/*
- * Invokes the callback function for each process
- */
-static void forEachProcess(ProcessCallback f, void* user_data) {
- DIR* dir;
- struct dirent* ptr;
-
- /*
- * To locate the children we scan /proc looking for files that have a
- * position integer as a filename.
- */
- if ((dir = opendir("/proc")) == NULL) {
- return;
- }
- while ((ptr = readdir(dir)) != NULL) {
- pid_t pid;
-
- /* skip current/parent directories */
- if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
- continue;
- }
-
- /* skip files that aren't numbers */
- pid = (pid_t)atoi(ptr->d_name);
- if ((int)pid <= 0) {
- continue;
- }
-
- /* invoke the callback */
- (*f)(pid, user_data);
- }
- closedir(dir);
-}
-
-
-/*
- * Returns the parent pid of a given pid, or -1 if not found
- */
-static pid_t getParent(pid_t pid) {
- char state;
- FILE* fp;
- char stat[2048];
- int statlen;
- char fn[32];
- int i, p;
- char* s;
-
- /*
- * try to open /proc/%d/stat
- */
- sprintf(fn, "/proc/%d/stat", pid);
- fp = fopen(fn, "r");
- if (fp == NULL) {
- return -1;
- }
-
- /*
- * The format is: pid (command) state ppid ...
- * As the command could be anything we must find the right most
- * ")" and then skip the white spaces that follow it.
- */
- statlen = fread(stat, 1, 2047, fp);
- stat[statlen] = '\0';
- fclose(fp);
- s = strrchr(stat, ')');
- if (s == NULL) {
- return -1;
- }
- do s++; while (isspace(*s));
- i = sscanf(s, "%c %d", &state, &p);
- return (pid_t)p;
-}
-
-
-/*
* Class: sun_tools_attach_VirtualMachineImpl
* Method: socket
* Signature: ()I
@@ -195,39 +111,6 @@
}
/*
- * Structure and callback function used to send a QUIT signal to all
- * children of a given process
- */
-typedef struct {
- pid_t ppid;
-} SendQuitContext;
-
-static void SendQuitCallback(const pid_t pid, void* user_data) {
- SendQuitContext* context = (SendQuitContext*)user_data;
- pid_t parent = getParent(pid);
- if (parent == context->ppid) {
- kill(pid, SIGQUIT);
- }
-}
-
-/*
- * Class: sun_tools_attach_VirtualMachineImpl
- * Method: sendQuitToChildrenOf
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sendQuitToChildrenOf
- (JNIEnv *env, jclass cls, jint pid)
-{
- SendQuitContext context;
- context.ppid = (pid_t)pid;
-
- /*
- * Iterate over all children of 'pid' and send a QUIT signal to each.
- */
- forEachProcess(SendQuitCallback, (void*)&context);
-}
-
-/*
* Class: sun_tools_attach_VirtualMachineImpl
* Method: sendQuitTo
* Signature: (I)V
@@ -255,6 +138,8 @@
uid_t uid, gid;
int res;
+ memset(&sb, 0, sizeof(struct stat64));
+
/*
* Check that the path is owned by the effective uid/gid of this
* process. Also check that group/other access is not allowed.
@@ -272,21 +157,21 @@
char msg[100];
jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE;
} else if (sb.st_gid != gid) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE;
} else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);
isError = JNI_TRUE;
}
if (isError) {
char buf[256];
- jio_snprintf(buf, sizeof(buf)-1, "well-known file %s is not secure: %s", p, msg);
+ snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg);
JNU_ThrowIOException(env, buf);
}
} else {
@@ -312,6 +197,7 @@
(JNIEnv *env, jclass cls, jint fd)
{
int res;
+ shutdown(fd, SHUT_RDWR);
RESTARTABLE(close(fd), res);
}
@@ -366,8 +252,8 @@
RESTARTABLE(write(fd, buf, len), n);
if (n > 0) {
- off += n;
- remaining -= n;
+ off += n;
+ remaining -= n;
} else {
JNU_ThrowIOExceptionWithLastError(env, "write");
return;
--- a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -281,8 +281,7 @@
}
private File createAttachFile(int pid) throws IOException {
- String fn = ".attach_pid" + pid;
- File f = new File(tmpdir, fn);
+ File f = new File(tmpdir, ".attach_pid" + pid);
createAttachFile0(f.getPath());
return f;
}
--- a/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.attach/macosx/native/libattach/VirtualMachineImpl.c Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,24 +23,20 @@
* questions.
*/
-#include "jni.h"
#include "jni_util.h"
-#include "jvm.h"
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syslimits.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <errno.h>
#include <unistd.h>
-#include <signal.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/syslimits.h>
-#include <sys/un.h>
-#include <fcntl.h>
#include "sun_tools_attach_VirtualMachineImpl.h"
@@ -144,6 +140,8 @@
uid_t uid, gid;
int res;
+ memset(&sb, 0, sizeof(struct stat));
+
/*
* Check that the path is owned by the effective uid/gid of this
* process. Also check that group/other access is not allowed.
@@ -161,21 +159,21 @@
char msg[100];
jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE;
} else if (sb.st_gid != gid) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE;
} else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);
isError = JNI_TRUE;
}
if (isError) {
char buf[256];
- jio_snprintf(buf, sizeof(buf)-1, "well-known file %s is not secure: %s", p, msg);
+ snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg);
JNU_ThrowIOException(env, buf);
}
} else {
@@ -201,6 +199,7 @@
(JNIEnv *env, jclass cls, jint fd)
{
int res;
+ shutdown(fd, SHUT_RDWR);
RESTARTABLE(close(fd), res);
}
@@ -255,8 +254,8 @@
RESTARTABLE(write(fd, buf, len), n);
if (n > 0) {
- off += n;
- remaining -= n;
+ off += n;
+ remaining -= n;
} else {
JNU_ThrowIOExceptionWithLastError(env, "write");
return;
--- a/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -225,7 +225,7 @@
return fd;
}
- // On Solaris/Linux a simple handshake is used to start the attach mechanism
+ // On Solaris a simple handshake is used to start the attach mechanism
// if not already started. The client creates a .attach_pid<pid> file in the
// target VM's working directory (or temporary directory), and the SIGQUIT
// handler checks for the file.
--- a/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c Tue Apr 17 18:18:53 2018 +0100
@@ -22,20 +22,19 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
+
+#include "jni_util.h"
+
+#include <sys/stat.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <door.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
+#include <unistd.h>
#include "sun_tools_attach_VirtualMachineImpl.h"
@@ -105,6 +104,8 @@
uid_t uid, gid;
int res;
+ memset(&sb, 0, sizeof(struct stat64));
+
/*
* Check that the path is owned by the effective uid/gid of this
* process. Also check that group/other access is not allowed.
@@ -122,21 +123,21 @@
char msg[100];
jboolean isError = JNI_FALSE;
if (sb.st_uid != uid) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
isError = JNI_TRUE;
} else if (sb.st_gid != gid) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
isError = JNI_TRUE;
} else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {
- jio_snprintf(msg, sizeof(msg)-1,
+ snprintf(msg, sizeof(msg),
"file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);
isError = JNI_TRUE;
}
if (isError) {
char buf[256];
- jio_snprintf(buf, sizeof(buf)-1, "well-known file %s is not secure: %s", p, msg);
+ snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg);
JNU_ThrowIOException(env, buf);
}
} else {
--- a/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.attach/windows/native/libattach/VirtualMachineImpl.c Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,16 +22,15 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
+
+#include "jni_util.h"
+
#include <windows.h>
#include <Sddl.h>
#include <string.h>
-#include "jni.h"
-#include "jni_util.h"
-
#include "sun_tools_attach_VirtualMachineImpl.h"
-
/* kernel32 */
typedef HINSTANCE (WINAPI* GetModuleHandleFunc) (LPCTSTR);
typedef FARPROC (WINAPI* GetProcAddressFunc)(HMODULE, LPCSTR);
@@ -303,9 +302,7 @@
LocalFree(sa.lpSecurityDescriptor);
if (hPipe == INVALID_HANDLE_VALUE) {
- char msg[256];
- _snprintf(msg, sizeof(msg), "CreateNamedPipe failed: %d", GetLastError());
- JNU_ThrowIOExceptionWithLastError(env, msg);
+ JNU_ThrowIOExceptionWithLastError(env, "CreateNamedPipe failed");
}
return (jlong)hPipe;
}
@@ -318,7 +315,7 @@
JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_closePipe
(JNIEnv *env, jclass cls, jlong hPipe)
{
- CloseHandle( (HANDLE)hPipe );
+ CloseHandle((HANDLE)hPipe);
}
/*
@@ -430,7 +427,7 @@
if ((*env)->ExceptionOccurred(env)) return;
}
}
- for (i=argsLen; i<MAX_ARGS; i++) {
+ for (i = argsLen; i < MAX_ARGS; i++) {
data.arg[i][0] = '\0';
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java Tue Apr 17 18:18:53 2018 +0100
@@ -380,9 +380,7 @@
public final int javaThreadAnchorOffset = getFieldOffset("JavaThread::_anchor", Integer.class, "JavaFrameAnchor");
public final int threadObjectOffset = getFieldOffset("JavaThread::_threadObj", Integer.class, "oop");
public final int osThreadOffset = getFieldOffset("JavaThread::_osthread", Integer.class, "OSThread*");
- public final int javaThreadDirtyCardQueueOffset = getFieldOffset("JavaThread::_dirty_card_queue", Integer.class, "DirtyCardQueue");
public final int threadIsMethodHandleReturnOffset = getFieldOffset("JavaThread::_is_method_handle_return", Integer.class, "int");
- public final int javaThreadSatbMarkQueueOffset = getFieldOffset("JavaThread::_satb_mark_queue", Integer.class);
public final int threadObjectResultOffset = getFieldOffset("JavaThread::_vm_result", Integer.class, "oop");
public final int jvmciCountersThreadOffset = getFieldOffset("JavaThread::_jvmci_counters", Integer.class, "jlong*");
public final int javaThreadReservedStackActivationOffset = getFieldOffset("JavaThread::_reserved_stack_activation", Integer.class, "address", intNotPresentInJDK8);
@@ -455,13 +453,6 @@
public final int frameInterpreterFrameSenderSpOffset = getConstant("frame::interpreter_frame_sender_sp_offset", Integer.class, intRequiredOnAMD64);
public final int frameInterpreterFrameLastSpOffset = getConstant("frame::interpreter_frame_last_sp_offset", Integer.class, intRequiredOnAMD64);
- private final int dirtyCardQueueBufferOffset = isJDK8 ? getFieldOffset("PtrQueue::_buf", Integer.class, "void**") : getConstant("dirtyCardQueueBufferOffset", Integer.class);
- private final int dirtyCardQueueIndexOffset = isJDK8 ? getFieldOffset("PtrQueue::_index", Integer.class, "size_t") : getConstant("dirtyCardQueueIndexOffset", Integer.class);
-
- private final int satbMarkQueueBufferOffset = getConstant("satbMarkQueueBufferOffset", Integer.class, intNotPresentInJDK8);
- private final int satbMarkQueueIndexOffset = getConstant("satbMarkQueueIndexOffset", Integer.class, intNotPresentInJDK8);
- private final int satbMarkQueueActiveOffset = isJDK8 ? getFieldOffset("PtrQueue::_active", Integer.class, "bool") : getConstant("satbMarkQueueActiveOffset", Integer.class, intNotPresentInJDK8);
-
public final int osThreadInterruptedOffset = getFieldOffset("OSThread::_interrupted", Integer.class, "jint");
public final long markOopDescHashShift = getConstant("markOopDesc::hash_shift", Long.class);
@@ -575,25 +566,11 @@
// G1 Collector Related Values.
- public int g1CardQueueIndexOffset() {
- return javaThreadDirtyCardQueueOffset + dirtyCardQueueIndexOffset;
- }
-
- public int g1CardQueueBufferOffset() {
- return javaThreadDirtyCardQueueOffset + dirtyCardQueueBufferOffset;
- }
-
- public int g1SATBQueueMarkingOffset() {
- return javaThreadSatbMarkQueueOffset + satbMarkQueueActiveOffset;
- }
-
- public int g1SATBQueueIndexOffset() {
- return javaThreadSatbMarkQueueOffset + (isJDK8 ? dirtyCardQueueIndexOffset : satbMarkQueueIndexOffset);
- }
-
- public int g1SATBQueueBufferOffset() {
- return javaThreadSatbMarkQueueOffset + (isJDK8 ? dirtyCardQueueBufferOffset : satbMarkQueueBufferOffset);
- }
+ public final int g1SATBQueueMarkingOffset = getConstant("G1ThreadLocalData::satb_mark_queue_active_offset", Integer.class);
+ public final int g1SATBQueueIndexOffset = getConstant("G1ThreadLocalData::satb_mark_queue_index_offset", Integer.class);
+ public final int g1SATBQueueBufferOffset = getConstant("G1ThreadLocalData::satb_mark_queue_buffer_offset", Integer.class);
+ public final int g1CardQueueIndexOffset = getConstant("G1ThreadLocalData::dirty_card_queue_index_offset", Integer.class);
+ public final int g1CardQueueBufferOffset = getConstant("G1ThreadLocalData::dirty_card_queue_buffer_offset", Integer.class);
public final int klassOffset = getFieldValue("java_lang_Class::_klass_offset", Integer.class, "int");
public final int arrayKlassOffset = getFieldValue("java_lang_Class::_array_klass_offset", Integer.class, "int");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java Tue Apr 17 08:54:17 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java Tue Apr 17 18:18:53 2018 +0100
@@ -631,12 +631,12 @@
@Fold
public static int g1CardQueueIndexOffset(@InjectedParameter GraalHotSpotVMConfig config) {
- return config.g1CardQueueIndexOffset();
+ return config.g1CardQueueIndexOffset;
}
@Fold
public static int g1CardQueueBufferOffset(@InjectedParameter GraalHotSpotVMConfig config) {
- return config.g1CardQueueBufferOffset();
+ return config.g1CardQueueBufferOffset;
}
@Fold
@@ -646,17 +646,17 @@
@Fold
public static int g1SATBQueueMarkingOffset(@InjectedParameter GraalHotSpotVMConfig config) {
- return config.g1SATBQueueMarkingOffset();
+ return config.g1SATBQueueMarkingOffset;
}
@Fold
public static int g1SATBQueueIndexOffset(@InjectedParameter GraalHotSpotVMConfig config) {
- return config.g1SATBQueueIndexOffset();
+ return config.g1SATBQueueIndexOffset;
}
@Fold
public static int g1SATBQueueBufferOffset(@InjectedParameter GraalHotSpotVMConfig config) {
- return config.g1SATBQueueBufferOffset();
+ return config.g1SATBQueueBufferOffset;
}
public static final LocationIdentity KLASS_SUPER_CHECK_OFFSET_LOCATION = NamedLocationIdentity.immutable("Klass::_super_check_offset");
--- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -856,9 +856,6 @@
vstate.check();
}
-// Parallel iteration not available unless INCLUDE_ALL_GCS
-#if INCLUDE_ALL_GCS
-
class OopStorageTestParIteration : public OopStorageTestIteration {
public:
WorkGang* workers();
@@ -1017,8 +1014,6 @@
vstate.check();
}
-#endif // INCLUDE_ALL_GCS
-
TEST_VM_F(OopStorageTestWithAllocation, delete_empty_blocks_safepoint) {
TestAccess::BlockList& active_list = TestAccess::active_list(_storage);
@@ -1384,4 +1379,3 @@
}
EXPECT_EQ(NULL_BLOCK, active_block);
}
-
--- a/test/hotspot/gtest/gc/shared/test_preservedMarks.cpp Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/gtest/gc/shared/test_preservedMarks.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018 Oracle and/or its affiliates. All rights reserved.
* 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/shared/preservedMarks.inline.hpp"
+#include "oops/oop.inline.hpp"
#include "unittest.hpp"
class ScopedDisabledBiasedLocking {
@@ -38,14 +39,14 @@
oopDesc _oop;
public:
- FakeOop() : _oop() { _oop.set_mark(originalMark()); }
+ FakeOop() : _oop() { _oop.set_mark_raw(originalMark()); }
oop get_oop() { return &_oop; }
- markOop mark() { return _oop.mark(); }
- void set_mark(markOop m) { _oop.set_mark(m); }
+ markOop mark() { return _oop.mark_raw(); }
+ void set_mark(markOop m) { _oop.set_mark_raw(m); }
void forward_to(oop obj) {
markOop m = markOopDesc::encode_pointer_as_mark(obj);
- _oop.set_mark(m);
+ _oop.set_mark_raw(m);
}
static markOop originalMark() { return markOop(markOopDesc::lock_mask_in_place); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/gtest/utilities/test_spinYield.cpp Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 "runtime/os.hpp"
+#include "utilities/ostream.hpp"
+#include "utilities/spinYield.hpp"
+#include "unittest.hpp"
+
+// Some basic tests of SpinYield, using comparison of report output with
+// expected results to verify state. This is all very hard-wired to the
+// current implementation of SpinYield, esp. the report function.
+
+static void check_report(const SpinYield* spinner, const char* expected) {
+ char buffer[100];
+ stringStream s(buffer, sizeof(buffer));
+ spinner->report(&s);
+ ASSERT_STREQ(expected, buffer);
+}
+
+TEST(SpinYield, no_waiting) {
+ SpinYield spinner;
+ check_report(&spinner, "no waiting");
+}
+
+TEST(SpinYield, one_wait) {
+ SpinYield spinner(100);
+ spinner.wait();
+ check_report(&spinner, os::is_MP() ? "spins = 1" : "yields = 1");
+}
+
+TEST(SpinYield, ten_waits) {
+ SpinYield spinner(100, 100);
+ for (unsigned i = 0; i < 10; ++i) {
+ spinner.wait();
+ }
+ check_report(&spinner, os::is_MP() ? "spins = 10" : "yields = 10");
+}
+
+TEST(SpinYield, two_yields) {
+ SpinYield spinner(0, 10);
+ spinner.wait();
+ spinner.wait();
+ check_report(&spinner, "yields = 2");
+}
+
+TEST(SpinYield, one_sleep) {
+ SpinYield spinner(0, 0);
+ spinner.wait();
+
+ char buffer[100];
+ stringStream s(buffer, sizeof(buffer));
+ spinner.report(&s);
+
+ const char* expected = "sleep = ";
+ ASSERT_TRUE(strncmp(expected, buffer, strlen(expected)) == 0);
+}
+
+TEST(SpinYield, one_spin_one_sleep) {
+ SpinYield spinner(1, 0);
+ spinner.wait();
+ spinner.wait();
+
+ char buffer[100];
+ stringStream s(buffer, sizeof(buffer));
+ spinner.report(&s);
+
+ const char* expected_MP = "spins = 1, sleep = ";
+ const char* expected_UP = "sleep = ";
+ const char* expected = os::is_MP() ? expected_MP : expected_UP;
+ ASSERT_TRUE(strncmp(expected, buffer, strlen(expected)) == 0);
+}
--- a/test/hotspot/jtreg/TEST.groups Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/TEST.groups Tue Apr 17 18:18:53 2018 +0100
@@ -177,7 +177,7 @@
tier1_runtime = \
runtime/ \
- -runtime/6626217/Test6626217.sh \
+ -runtime/6626217/bug_21227.java \
-runtime/7100935 \
-runtime/7158988/FieldMonitor.java \
-runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java \
@@ -265,7 +265,8 @@
-:tier1_runtime \
-:tier1_serviceability \
-:hotspot_tier2_runtime_platform_agnostic \
- -runtime/signal
+ -runtime/signal \
+ -runtime/NMT/MallocStressTest.java
hotspot_tier2_runtime_platform_agnostic = \
runtime/SelectionResolution \
--- a/test/hotspot/jtreg/runtime/6626217/Loader2.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/6626217/Loader2.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
print("Fetching the implementation of "+name);
int old = _recur;
try {
- FileInputStream fi = new FileInputStream(name+".impl2");
+ FileInputStream fi = new FileInputStream(name+".class");
byte result[] = new byte[fi.available()];
fi.read(result);
--- a/test/hotspot/jtreg/runtime/6626217/Test6626217.sh Tue Apr 17 08:54:17 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-#
-# Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-
-# @test @(#)Test6626217.sh
-# @bug 6626217
-# @summary Loader-constraint table allows arrays instead of only the base-classes
-# @run shell Test6626217.sh
-#
-## some tests require path to find test source dir
-if [ "${TESTSRC}" = "" ]
-then
- TESTSRC=${PWD}
- echo "TESTSRC not set. Using "${TESTSRC}" as default"
-fi
-echo "TESTSRC=${TESTSRC}"
-## Adding common setup Variables for running shell tests.
-. ${TESTSRC}/../../test_env.sh
-
-JAVA=${TESTJAVA}${FS}bin${FS}java
-JAVAC=${COMPILEJAVA}${FS}bin${FS}javac
-
-# Current directory is scratch directory, copy all the test source there
-# (for the subsequent moves to work).
-${CP} ${TESTSRC}${FS}* ${THIS_DIR}
-
-# A Clean Compile: this line will probably fail within jtreg as have a clean dir:
-${RM} -f *.class *.impl many_loader.java
-
-# Make sure that the compilation steps occurs in the future as not to allow fast systems
-# to copy and compile bug_21227.java so fast as to make the class and java have the same
-# time stamp, which later on would make the compilation step of many_loader.java fail
-sleep 2
-
-# Compile all the usual suspects, including the default 'many_loader'
-${CP} many_loader1.java.foo many_loader.java
-${JAVAC} ${TESTJAVACOPTS} -Xlint *.java
-
-# Rename the class files, so the custom loader (and not the system loader) will find it
-${MV} from_loader2.class from_loader2.impl2
-
-# Compile the next version of 'many_loader'
-${MV} many_loader.class many_loader.impl1
-${CP} many_loader2.java.foo many_loader.java
-${JAVAC} ${TESTJAVACOPTS} -Xlint many_loader.java
-
-# Rename the class file, so the custom loader (and not the system loader) will find it
-${MV} many_loader.class many_loader.impl2
-${MV} many_loader.impl1 many_loader.class
-${RM} many_loader.java
-
-${JAVA} ${TESTOPTS} -Xverify -Xint -cp . bug_21227 >test.out 2>&1
-grep "loader constraint" test.out
-exit $?
-
--- a/test/hotspot/jtreg/runtime/6626217/bug_21227.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/6626217/bug_21227.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,63 +22,85 @@
*
*/
+/**
+ * @test
+ * @bug 6626217
+ * @summary Loader-constraint table allows arrays instead of only the base-classes
+ * @library /test/lib
+ * @compile bug_21227.java from_loader2.java
+ * @run driver ClassFileInstaller from_loader2
+ * @compile impl2/many_loader.java
+ * @run driver ClassFileInstaller many_loader
+ * @compile many_loader.java
+ * @run main/othervm -Xverify -Xint bug_21227
+ */
+
import java.lang.reflect.*;
import java.security.*;
abstract public class bug_21227 {
- // Jam anything you want in here, it will be cast to a You_Have_Been_P0wned
- public static Object _p0wnee;
+ // Jam anything you want in here, it will be cast to a You_Have_Been_P0wned.
+ public static Object _p0wnee;
- public static void main(String argv[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
- System.out.println("Warmup");
+ public static void main(String argv[]) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+ try {
+ System.out.println("Warmup");
- // Make a Class 'many_loader' under the default loader
- bug_21227 bug = new many_loader();
+ // Make a Class 'many_loader' under the default loader.
+ bug_21227 bug = new many_loader();
- // Some classes under a new Loader, LOADER2, including another version of 'many_loader'
- ClassLoader LOADER2 = new Loader2();
- Class clazz2 = LOADER2.loadClass("from_loader2");
- IFace iface = (IFace)clazz2.newInstance();
+ // Some classes under a new Loader, LOADER2, including another version of 'many_loader'.
+ ClassLoader LOADER2 = new Loader2();
+ Class clazz2 = LOADER2.loadClass("from_loader2");
+ IFace iface = (IFace)clazz2.newInstance();
- // Set the victim, a String of length 6
- String s = "victim";
- _p0wnee = s;
+ // Set the victim, a String of length 6.
+ String s = "victim";
+ _p0wnee = s;
- // Go cast '_p0wnee' to type You_Have_Been_P0wned
- many_loader[] x2 = bug.make(iface);
+ // Go cast '_p0wnee' to type You_Have_Been_P0wned.
+ many_loader[] x2 = bug.make(iface);
- many_loader b = x2[0];
+ many_loader b = x2[0];
- // Make it clear that the runtime type many_loader (what we get from the
- // array X2) varies from the static type of many_loader.
- Class cl1 = b.getClass();
- ClassLoader ld1 = cl1.getClassLoader();
- Class cl2 = many_loader.class;
- ClassLoader ld2 = cl2.getClassLoader();
- System.out.println("bug.make() "+ld1+":"+cl1);
- System.out.println("many_loader "+ld2+":"+cl2);
+ // Make it clear that the runtime type many_loader (what we get from the
+ // array X2) varies from the static type of many_loader.
+ Class cl1 = b.getClass();
+ ClassLoader ld1 = cl1.getClassLoader();
+ Class cl2 = many_loader.class;
+ ClassLoader ld2 = cl2.getClassLoader();
+ System.out.println("bug.make() "+ld1+":"+cl1);
+ System.out.println("many_loader "+ld2+":"+cl2);
+
+ // Read the victims guts out.
+ You_Have_Been_P0wned q = b._p0wnee;
+ System.out.println("q._a = 0x"+Integer.toHexString(q._a));
+ System.out.println("q._b = 0x"+Integer.toHexString(q._b));
+ System.out.println("q._c = 0x"+Integer.toHexString(q._c));
+ System.out.println("q._d = 0x"+Integer.toHexString(q._d));
- // Read the victims guts out
- You_Have_Been_P0wned q = b._p0wnee;
- System.out.println("q._a = 0x"+Integer.toHexString(q._a));
- System.out.println("q._b = 0x"+Integer.toHexString(q._b));
- System.out.println("q._c = 0x"+Integer.toHexString(q._c));
- System.out.println("q._d = 0x"+Integer.toHexString(q._d));
+ System.out.println("I will now crash the VM:");
+ // On 32-bit HotSpot Java6 this sets the victim String length shorter, then crashes the VM.
+ //q._c = 3;
+ q._a = -1;
- System.out.println("I will now crash the VM:");
- // On 32-bit HotSpot Java6 this sets the victim String length shorter, then crashes the VM
- //q._c = 3;
- q._a = -1;
-
- System.out.println(s);
+ System.out.println(s);
+ throw new RuntimeException("Expected LinkageError was not thrown.");
+ } catch (LinkageError e) {
+ String errorMsg = e.getMessage();
+ if (!errorMsg.contains("loader constraint")) {
+ throw new RuntimeException("Error message of LinkageError does not contain \"loader constraint\":" +
+ errorMsg);
+ }
+ System.out.println("Passed with message: " + errorMsg);
+ }
+ }
- }
-
- // I need to compile (hence call in a loop) a function which returns a value
- // loaded from classloader other than the system one. The point of this
- // call is to give me an abstract 'hook' into a function loaded with a
- // foreign loader.
- public abstract many_loader[] make( IFace iface ); // abstract factory
+ // I need to compile (hence call in a loop) a function which returns a value
+ // loaded from classloader other than the system one. The point of this
+ // call is to give me an abstract 'hook' into a function loaded with a
+ // foreign loader.
+ public abstract many_loader[] make(IFace iface); // abstract factory
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/6626217/impl2/many_loader.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ *
+ */
+
+// A simple class to extend an abstract class and get loaded with different
+// loaders. This class is loaded via LOADER2. A similar named class will
+// be loaded via LOADER1.
+public class many_loader extends bug_21227 {
+ final Object _ref_to_be_p0wned;
+
+ many_loader() {
+ _ref_to_be_p0wned = bug_21227._p0wnee;
+ System.out.println("Gonna hack this thing: " + _ref_to_be_p0wned.toString() );
+ }
+
+ // I need to compile (hence call in a loop) a function which returns a value
+ // loaded from classloader other than the system one. The point of this
+ // call is to give me an abstract 'hook' into a function loaded with a
+ // foreign loader.
+ public many_loader[] make(IFace iface) {
+ throw new Error("do not call me");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/6626217/many_loader.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ *
+ */
+
+// A simple class to extend an abstract class and get loaded with different
+// loaders. This class is loaded via LOADER1. A similar named class will
+// be loaded via LOADER2.
+public class many_loader extends bug_21227 {
+ public You_Have_Been_P0wned _p0wnee;
+
+ // I need to compile (hence call in a loop) a function which returns a value
+ // loaded from classloader other than the system one. The point of this
+ // call is to give me an abstract 'hook' into a function loaded with a
+ // foreign loader.
+
+ // The original 'make(boolean)' returns a bug_21227. The VM will inject a
+ // synthetic method to up-cast the returned 'from_loader1' into a
+ // 'bug_21227'.
+ public many_loader[] make(IFace iface) {
+ // This function needs to return a value known to be loaded from LOADER2.
+ // Since I need to use a yet different loader, I need to make an unknown
+ // foreign call. In this case I'll be using an interface to make the
+ // unknown call, with but a single implementor so the compiler can do the
+ // upcast statically.
+ return iface==null ? null : iface.gen();
+ }
+}
--- a/test/hotspot/jtreg/runtime/6626217/many_loader1.java.foo Tue Apr 17 08:54:17 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * 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.
- *
- */
-
-// A simple class to extend an abstract class and get loaded with different
-// loaders. This class is loaded via LOADER1. A similar named class will
-// be loaded via LOADER2.
-public class many_loader extends bug_21227 {
- public You_Have_Been_P0wned _p0wnee;
-
- // I need to compile (hence call in a loop) a function which returns a value
- // loaded from classloader other than the system one. The point of this
- // call is to give me an abstract 'hook' into a function loaded with a
- // foreign loader.
-
- // The original 'make(boolean)' returns a bug_21227. The VM will inject a
- // synthetic method to up-cast the returned 'from_loader1' into a
- // 'bug_21227'.
- public many_loader[] make( IFace iface ) {
- // This function needs to return a value known to be loaded from LOADER2.
- // Since I need to use a yet different loader, I need to make an unknown
- // foreign call. In this case I'll be using an interface to make the
- // unknown call, with but a single implementor so the compiler can do the
- // upcast statically.
- return iface==null ? null : iface.gen();
- }
-}
--- a/test/hotspot/jtreg/runtime/6626217/many_loader2.java.foo Tue Apr 17 08:54:17 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- * 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.
- *
- */
-
-// A simple class to extend an abstract class and get loaded with different
-// loaders. This class is loaded via LOADER2. A similar named class will
-// be loaded via LOADER1.
-public class many_loader extends bug_21227 {
- final Object _ref_to_be_p0wned;
-
- many_loader() {
- _ref_to_be_p0wned = bug_21227._p0wnee;
- System.out.println("Gonna hack this thing: " + _ref_to_be_p0wned.toString() );
- }
-
- // I need to compile (hence call in a loop) a function which returns a value
- // loaded from classloader other than the system one. The point of this
- // call is to give me an abstract 'hook' into a function loaded with a
- // foreign loader.
- public many_loader[] make( IFace iface ) {
- throw new Error("do not call me");
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/ClassFile/PreviewVersion.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 8198908
+ * @summary Check that preview minor version and --enable-preview are handled
+ * correctly.
+ * @modules java.base/jdk.internal.misc
+ * @library /test/lib
+ * @run main PreviewVersion
+ */
+
+import java.io.File;
+import jdk.test.lib.compiler.InMemoryJavaCompiler;
+import jdk.test.lib.ByteCodeLoader;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class PreviewVersion {
+
+ public static void main(String args[]) throws Throwable {
+ System.out.println("Regression test for bug 8198908");
+
+ byte klassbuf[] = InMemoryJavaCompiler.compile("PVTest",
+ "public class PVTest { " +
+ "public static void main(String argv[]) { " +
+ "System.out.println(\"Hi!\"); } }");
+
+ // Set class's minor version to 65535.
+ klassbuf[4] = -1;
+ klassbuf[5] = -1;
+
+ // Run the test. This should fail because --enable-preview is not specified.
+ ClassFileInstaller.writeClassToDisk("PVTest", klassbuf, System.getProperty("test.classes"));
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-cp", "." + File.pathSeparator + System.getProperty("test.classes"), "PVTest");
+ OutputAnalyzer oa = new OutputAnalyzer(pb.start());
+ oa.shouldContain("Preview features are not enabled");
+ oa.shouldHaveExitValue(1);
+
+ // This should be successful because --enable-preview is specified.
+ pb = ProcessTools.createJavaProcessBuilder("--enable-preview",
+ "-cp", "." + File.pathSeparator + System.getProperty("test.classes"), "PVTest");
+ oa = new OutputAnalyzer(pb.start());
+ oa.shouldContain("Hi!");
+
+ // Test -Xlog:class+preview
+ pb = ProcessTools.createJavaProcessBuilder("--enable-preview", "-Xlog:class+preview",
+ "-cp", "." + File.pathSeparator + System.getProperty("test.classes"), "PVTest");
+ oa = new OutputAnalyzer(pb.start());
+ oa.shouldContain("[info][class,preview] Loading preview feature type PVTest");
+
+ // Subtract 1 from class's major version. The class should fail to load
+ // because its major_version does not match the JVM current version.
+ int prev_major_version = Runtime.version().feature() - 1;
+ klassbuf[6] = (byte)((prev_major_version >> 8) & 0xff);
+ klassbuf[7] = (byte)(prev_major_version & 0xff);
+ try {
+ ByteCodeLoader.load("PVTest", klassbuf);
+ throw new RuntimeException("UnsupportedClassVersionError exception not thrown");
+ } catch (java.lang.UnsupportedClassVersionError e) {
+ if (!e.getMessage().contains("compiled with preview features that are unsupported")) {
+ throw new RuntimeException(
+ "Wrong UnsupportedClassVersionError exception: " + e.getMessage());
+ }
+ }
+
+ // Set class's major version to 45. The class should load because class
+ // version 45.65535 is valid.
+ klassbuf[6] = 0;
+ klassbuf[7] = 45;
+ try {
+ ByteCodeLoader.load("PVTest", klassbuf);
+ } catch (java.lang.UnsupportedClassVersionError e) {
+ throw new RuntimeException(
+ "Unexpected UnsupportedClassVersionError exception thrown: " + e.getMessage());
+ }
+
+ // Check that a class with a recent older major version and a non-zero
+ // minor version fails to load.
+ klassbuf[6] = 0;
+ klassbuf[7] = 53;
+ klassbuf[4] = 0;
+ klassbuf[5] = 2;
+ try {
+ ByteCodeLoader.load("PVTest", klassbuf);
+ throw new RuntimeException("UnsupportedClassVersionError exception not thrown");
+ } catch (java.lang.UnsupportedClassVersionError e) {
+ if (!e.getMessage().contains("was compiled with an invalid non-zero minor version")) {
+ throw new RuntimeException(
+ "Wrong UnsupportedClassVersionError exception: " + e.getMessage());
+ }
+ }
+ }
+}
--- a/test/hotspot/jtreg/runtime/appcds/JarBuilder.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/JarBuilder.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,9 +32,11 @@
*/
import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.compiler.CompilerUtils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import java.io.File;
+import java.nio.file.Path;
import java.util.ArrayList;
import sun.tools.jar.Main;
@@ -145,6 +147,21 @@
}
}
+ public static void createModularJar(String jarPath,
+ String classesDir,
+ String mainClass) throws Exception {
+ ArrayList<String> argList = new ArrayList<String>();
+ argList.add("--create");
+ argList.add("--file=" + jarPath);
+ if (mainClass != null) {
+ argList.add("--main-class=" + mainClass);
+ }
+ argList.add("-C");
+ argList.add(classesDir);
+ argList.add(".");
+ createJar(argList);
+ }
+
private static void createJar(ArrayList<String> args) {
if (DEBUG) printIterable("createJar args: ", args);
@@ -190,6 +207,23 @@
output.shouldHaveExitValue(0);
}
+ public static void compileModule(Path src,
+ Path dest,
+ String modulePathArg // arg to --module-path
+ ) throws Exception {
+ boolean compiled = false;
+ if (modulePathArg == null) {
+ compiled = CompilerUtils.compile(src, dest);
+ } else {
+ compiled = CompilerUtils.compile(src, dest,
+ "--module-path", modulePathArg);
+ }
+ if (!compiled) {
+ throw new RuntimeException("module did not compile");
+ }
+ }
+
+
public static void signJar() throws Exception {
String keyTool = JDKToolFinder.getJDKTool("keytool");
String jarSigner = JDKToolFinder.getJDKTool("jarsigner");
--- a/test/hotspot/jtreg/runtime/appcds/TestCommon.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/TestCommon.java Tue Apr 17 18:18:53 2018 +0100
@@ -200,13 +200,18 @@
return new Result(opts, runWithArchive(opts));
}
-
public static OutputAnalyzer exec(String appJar, String... suffix) throws Exception {
AppCDSOptions opts = (new AppCDSOptions()).setAppJar(appJar);
opts.addSuffix(suffix);
return runWithArchive(opts);
}
+ public static Result runWithModules(String prefix[], String upgrademodulepath, String modulepath,
+ String mid, String... testClassArgs) throws Exception {
+ AppCDSOptions opts = makeModuleOptions(prefix, upgrademodulepath, modulepath,
+ mid, testClassArgs);
+ return new Result(opts, runWithArchive(opts));
+ }
public static OutputAnalyzer execAuto(String... suffix) throws Exception {
AppCDSOptions opts = (new AppCDSOptions());
@@ -220,10 +225,9 @@
return runWithArchive(opts);
}
- public static OutputAnalyzer execModule(String prefix[], String upgrademodulepath, String modulepath,
- String mid, String... testClassArgs)
- throws Exception {
+ private static AppCDSOptions makeModuleOptions(String prefix[], String upgrademodulepath, String modulepath,
+ String mid, String testClassArgs[]) {
AppCDSOptions opts = (new AppCDSOptions());
opts.addPrefix(prefix);
@@ -234,7 +238,14 @@
"-p", modulepath, "-m", mid);
}
opts.addSuffix(testClassArgs);
+ return opts;
+ }
+ public static OutputAnalyzer execModule(String prefix[], String upgrademodulepath, String modulepath,
+ String mid, String... testClassArgs)
+ throws Exception {
+ AppCDSOptions opts = makeModuleOptions(prefix, upgrademodulepath, modulepath,
+ mid, testClassArgs);
return runWithArchive(opts);
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/CheckUnsupportedDumpingOptions.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/CheckUnsupportedDumpingOptions.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,20 +40,15 @@
public class CheckUnsupportedDumpingOptions {
private static final String[] jigsawOptions = {
- "-m",
"--limit-modules",
- "--module-path",
"--upgrade-module-path",
"--patch-module"
};
private static final String[] optionValues = {
"mymod",
- "mymod",
- "mydir",
".",
"java.naming=javax.naming.spi.NamingManger"
};
- private static final int infoIdx = 1;
public static void main(String[] args) throws Exception {
String source = "package javax.naming.spi; " +
@@ -71,31 +66,11 @@
String appClasses[] = {"Hello"};
for (int i = 0; i < jigsawOptions.length; i++) {
OutputAnalyzer output;
- if (i == 5) {
- // --patch-module
- output = TestCommon.dump(appJar, appClasses, "-Xlog:cds,cds+hashtables",
- jigsawOptions[i] + optionValues[i] + appJar);
- } else {
- output = TestCommon.dump(appJar, appClasses, "-Xlog:cds,cds+hashtables",
- jigsawOptions[i], optionValues[i]);
- }
- if (i < infoIdx) {
- output.shouldContain("Cannot use the following option " +
- "when dumping the shared archive: " + jigsawOptions[i])
- .shouldHaveExitValue(1);
- } else {
- output.shouldContain("Info: the " + jigsawOptions[i] +
- " option is ignored when dumping the shared archive");
- if (optionValues[i].equals("mymod")) {
- // java will throw FindException for a module
- // which cannot be found during init_phase2() of vm init
- output.shouldHaveExitValue(1)
- .shouldContain("java.lang.module.FindException: Module mymod not found");
- } else {
- output.shouldHaveExitValue(0);
- }
- }
+ output = TestCommon.dump(appJar, appClasses, "-Xlog:cds,cds+hashtables",
+ jigsawOptions[i], optionValues[i]);
+ output.shouldContain("Cannot use the following option " +
+ "when dumping the shared archive: " + jigsawOptions[i])
+ .shouldHaveExitValue(1);
}
}
}
-
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/JigsawOptionsCombo.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/JigsawOptionsCombo.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -69,8 +69,7 @@
private ArrayList<TestCase> testCaseTable = new ArrayList<TestCase>();
public static String infoDuringDump(String option) {
- return "Info: the " + option +
- " option is ignored when dumping the shared archive";
+ return "Cannot use the following option when dumping the shared archive: " + option;
}
public void runTests() throws Exception {
@@ -78,7 +77,7 @@
testCaseTable.add(new TestCase(
"basic: Basic dump and execute, to verify the test plumbing works",
"", "", 0,
- "", "", 0) );
+ "", "", 0, true) );
String bcpArg = "-Xbootclasspath/a:" +
TestCommon.getTestJar("hello_more.jar");
@@ -86,51 +85,50 @@
testCaseTable.add(new TestCase(
"Xbootclasspath/a: is OK for both dump and run time",
bcpArg, "", 0,
- bcpArg, "", 0) );
+ bcpArg, "", 0, true) );
testCaseTable.add(new TestCase(
"module-path-01: --module-path is ignored for dump time",
- "--module-path mods",
- infoDuringDump("--module-path"), 0,
- null, null, 0) );
+ "--module-path mods", "", 0,
+ null, null, 0, true) );
testCaseTable.add(new TestCase(
"module-path-02: --module-path is ok for run time",
"", "", 0,
- "--module-path mods", "", 0) );
+ "--module-path mods", "", 0, true) );
testCaseTable.add(new TestCase(
"add-modules-01: --add-modules is ok at dump time",
"--add-modules java.management",
"", 0,
- null, null, 0) );
+ null, null, 0, true) );
testCaseTable.add(new TestCase(
"add-modules-02: --add-modules is ok at run time",
"", "", 0,
- "--add-modules java.management", "", 0) );
+ "--add-modules java.management", "", 0, true) );
testCaseTable.add(new TestCase(
"limit-modules-01: --limit-modules is ignored at dump time",
"--limit-modules java.base",
- infoDuringDump("--limit-modules"), 0,
- null, null, 0) );
+ infoDuringDump("--limit-modules"), 1,
+ null, null, 0, true) );
testCaseTable.add(new TestCase(
"limit-modules-02: --limit-modules is ok at run time",
"", "", 0,
- "--limit-modules java.base", "", 0) );
+ "--limit-modules java.base", "", 0, false) );
testCaseTable.add(new TestCase(
"upgrade-module-path-01: --upgrade-module-path is ignored at dump time",
"--upgrade-module-path mods",
- infoDuringDump("--upgrade-module-path"), 0,
- null, null, 0) );
+ infoDuringDump("--upgrade-module-path"), 1,
+ null, null, 0, true) );
testCaseTable.add(new TestCase(
"-upgrade-module-path-module-path-02: --upgrade-module-path is ok at run time",
"", "", 0,
- "--upgrade-module-path mods", "", 0) );
+ "--upgrade-module-path mods", "", 0, false) );
for (TestCase tc : testCaseTable) tc.execute();
}
@@ -145,6 +143,7 @@
String runTimeArgs;
String runTimeExpectedOutput;
int runTimeExpectedExitValue;
+ boolean sharingOn;
private String appJar = TestCommon.getTestJar("hello.jar");
private String appClasses[] = {"Hello"};
@@ -152,7 +151,8 @@
public TestCase(String description,
String dumpTimeArgs, String dumpTimeExpectedOutput, int dumpTimeExpectedExitValue,
- String runTimeArgs, String runTimeExpectedOutput, int runTimeExpectedExitValue) {
+ String runTimeArgs, String runTimeExpectedOutput, int runTimeExpectedExitValue,
+ boolean sharingOn) {
this.description = description;
this.dumpTimeArgs = dumpTimeArgs;
@@ -161,6 +161,7 @@
this.runTimeArgs = runTimeArgs;
this.runTimeExpectedOutput = runTimeExpectedOutput;
this.runTimeExpectedExitValue = runTimeExpectedExitValue;
+ this.sharingOn = sharingOn;
}
@@ -183,7 +184,13 @@
OutputAnalyzer execOutput = TestCommon.exec(appJar, getRunOptions());
if (runTimeExpectedExitValue == 0) {
- TestCommon.checkExec(execOutput, runTimeExpectedOutput, "Hello World");
+ if (sharingOn) {
+ TestCommon.checkExec(execOutput, runTimeExpectedOutput, "Hello World");
+ } else {
+ execOutput.shouldHaveExitValue(0)
+ .shouldContain(runTimeExpectedOutput)
+ .shouldContain("Hello World");
+ }
} else {
execOutput.shouldMatch(dumpTimeExpectedOutput);
execOutput.shouldHaveExitValue(dumpTimeExpectedExitValue);
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/AppClassInCP.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/AppClassInCP.java Tue Apr 17 18:18:53 2018 +0100
@@ -86,7 +86,8 @@
"--patch-module=java.naming=" + moduleJar,
"-Xlog:class+load",
"PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello");
- TestCommon.checkDump(output, "Loading classes to share");
+ output.shouldHaveExitValue(1)
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
String classPath = appJar + File.pathSeparator + classDir;
System.out.println("classPath: " + classPath);
@@ -96,9 +97,6 @@
"--patch-module=java.naming=" + moduleJar,
"-Xlog:class+load",
"PatchMain", "javax.naming.spi.NamingManager", "mypackage.Hello")
- .assertNormalExit(
- "I pass!",
- "Hello!",
- "Hello source: shared objects file");
+ .assertSilentlyDisabledCDS(0, "I pass!", "Hello!");
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/CustomPackage.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/CustomPackage.java Tue Apr 17 18:18:53 2018 +0100
@@ -70,7 +70,8 @@
"-Xlog:class+load",
"-Xlog:class+path=info",
"PatchMain", "javax.naming.myspi.NamingManager");
- TestCommon.checkDump(output, "Preload Warning: Cannot find javax/naming/myspi/NamingManager");
+ output.shouldHaveExitValue(1)
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
@@ -78,6 +79,6 @@
"-Xlog:class+load",
"-Xlog:class+path=info",
"PatchMain", "javax.naming.myspi.NamingManager")
- .assertNormalExit("I pass!");
+ .assertSilentlyDisabledCDS(0, "I pass!");
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/MismatchedPatchModule.java Tue Apr 17 18:18:53 2018 +0100
@@ -62,41 +62,18 @@
JarBuilder.build("javanaming", "javax/naming/spi/NamingManager");
moduleJar = TestCommon.getTestJar("javanaming.jar");
- // Case 1: --patch-module specified for dump time and run time
+ // Case 1: --patch-module specified for dump time
System.out.println("Case 1: --patch-module specified for dump time and run time");
OutputAnalyzer output =
TestCommon.dump(null,
TestCommon.list("javax/naming/spi/NamingManager"),
"--patch-module=java.naming=" + moduleJar,
"PatchMain", "javax.naming.spi.NamingManager");
- TestCommon.checkDump(output, "Loading classes to share");
-
- // javax.naming.spi.NamingManager is not patched at runtime
- TestCommon.run(
- "-XX:+UnlockDiagnosticVMOptions",
- "--patch-module=java.naming2=" + moduleJar,
- "-Xlog:class+path=info",
- "PatchMain", "javax.naming.spi.NamingManager")
- .assertNormalExit(o -> o.shouldNotContain("I pass!"));
+ output.shouldHaveExitValue(1)
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
- // Case 2: --patch-module specified for dump time but not for run time
- System.out.println("Case 2: --patch-module specified for dump time but not for run time");
- output =
- TestCommon.dump(null,
- TestCommon.list("javax/naming/spi/NamingManager"),
- "--patch-module=java.naming=" + moduleJar,
- "PatchMain", "javax.naming.spi.NamingManager");
- TestCommon.checkDump(output, "Loading classes to share");
-
- // javax.naming.spi.NamingManager is not patched at runtime
- TestCommon.run(
- "-XX:+UnlockDiagnosticVMOptions",
- "-Xlog:class+path=info",
- "PatchMain", "javax.naming.spi.NamingManager")
- .assertNormalExit(o -> o.shouldNotContain("I pass!"));
-
- // Case 3: --patch-module specified for run time but not for dump time
- System.out.println("Case 3: --patch-module specified for run time but not for dump time");
+ // Case 2: --patch-module specified for run time but not for dump time
+ System.out.println("Case 2: --patch-module specified for run time but not for dump time");
output =
TestCommon.dump(null,
TestCommon.list("javax/naming/spi/NamingManager"),
@@ -107,26 +84,9 @@
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
"--patch-module=java.naming=" + moduleJar,
- "-Xlog:class+path=info",
- "PatchMain", "javax.naming.spi.NamingManager")
- .assertNormalExit("I pass!");
-
- // Case 4: mismatched --patch-module entry counts between dump time and run time
- System.out.println("Case 4: mismatched --patch-module entry counts between dump time and run time");
- output =
- TestCommon.dump(null,
- TestCommon.list("javax/naming/spi/NamingManager"),
- "--patch-module=java.naming=" + moduleJar,
- "PatchMain", "javax.naming.spi.NamingManager");
- TestCommon.checkDump(output, "Loading classes to share");
-
- // javax.naming.spi.NamingManager is patched at runtime
- TestCommon.run(
- "-XX:+UnlockDiagnosticVMOptions",
- "--patch-module=java.naming=" + moduleJar,
"--patch-module=java.naming2=" + moduleJar,
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager")
- .assertNormalExit("I pass!");
+ .assertSilentlyDisabledCDS(0, "I pass!");
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchDir.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchDir.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -67,7 +67,7 @@
"--patch-module=java.naming=" + moduleJar,
"-Xlog:class+load",
"PatchMain", "javax.naming.spi.NamingManager")
- .shouldContain("Loading classes to share")
- .shouldHaveExitValue(0);
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module")
+ .shouldHaveExitValue(1);
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/PatchJavaBase.java Tue Apr 17 18:18:53 2018 +0100
@@ -62,7 +62,8 @@
TestCommon.dump(null, null,
"--patch-module=java.base=" + moduleJar,
"PatchMain", "java.lang.NewClass");
- TestCommon.checkDump(output, "Loading classes to share");
+ output.shouldHaveExitValue(1)
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/Simple.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/Simple.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,7 +68,8 @@
"-Xlog:class+load",
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager");
- TestCommon.checkDump(output, "Loading classes to share");
+ output.shouldHaveExitValue(1)
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
@@ -76,6 +77,6 @@
"-Xlog:class+load",
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager")
- .assertNormalExit("I pass!");
+ .assertSilentlyDisabledCDS(0, "I pass!");
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/SubClassOfPatchedClass.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/SubClassOfPatchedClass.java Tue Apr 17 18:18:53 2018 +0100
@@ -88,7 +88,8 @@
"--patch-module=java.naming=" + moduleJar,
"-Xlog:class+load",
"PatchMain", "javax.naming.Reference", "mypackage.MyReference");
- TestCommon.checkDump(output, "Loading classes to share");
+ output.shouldHaveExitValue(1)
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
String classPath = appJar + File.pathSeparator + classDir;
System.out.println("classPath: " + classPath);
@@ -98,8 +99,6 @@
"--patch-module=java.naming=" + moduleJar,
"-Xlog:class+load",
"PatchMain", "javax.naming.Reference", "mypackage.MyReference")
- .assertNormalExit(
- "I pass!",
- "MyReference source: file:");
+ .assertSilentlyDisabledCDS(0, "MyReference source: file:", "I pass!");
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/TwoJars.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/PatchModule/TwoJars.java Tue Apr 17 18:18:53 2018 +0100
@@ -87,7 +87,8 @@
"-Xlog:class+load",
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager");
- TestCommon.checkDump(output, "Loading classes to share");
+ output.shouldHaveExitValue(1)
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
TestCommon.run(
"-XX:+UnlockDiagnosticVMOptions",
@@ -95,6 +96,6 @@
"-Xlog:class+load",
"-Xlog:class+path=info",
"PatchMain", "javax.naming.spi.NamingManager")
- .assertNormalExit("I pass");
+ .assertSilentlyDisabledCDS(0, "I pass!");
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/BootAppendTests.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,29 +145,32 @@
// Test #3: A class in excluded package defined in boot module
// - should be loaded from the -Xbootclasspath/a by the boot classloader
public static void testBootAppendExcludedModuleClassWithoutAppCDS() throws Exception {
- CDSOptions opts = (new CDSOptions())
- .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar,
- "--limit-modules", "java.base")
- .setArchiveName(testArchiveName)
- .addSuffix(MAIN_CLASS, "Test #3", BOOT_APPEND_MODULE_CLASS, "true", "BOOT");
-
- CDSTestUtils.runWithArchiveAndCheck(opts);
+ TestCommon.run(
+ "-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar,
+ "-Xlog:class+load=info",
+ "--limit-modules", "java.base",
+ MAIN_CLASS, "Test #3", BOOT_APPEND_MODULE_CLASS, "true", "BOOT")
+ .assertSilentlyDisabledCDS(out -> {
+ out.shouldHaveExitValue(0)
+ .shouldMatch(".class.load. sun.nio.cs.ext.MyClass source:.*bootAppend.jar");
+ });
}
// Test #4: A shared class in excluded package that's archived from
// -Xbootclasspath/a
- // - should be loaded from the archive by the bootstrap classloader
+ // - should be loaded from the jar since AppCDS will be disabled with
+ // the --limit-modules option
public static void testBootAppendExcludedModuleClassWithAppCDS() throws Exception {
- OutputAnalyzer output = TestCommon.exec(
- appJar,
- "-Xbootclasspath/a:" + bootAppendJar,
+ TestCommon.run(
+ "-cp", appJar, "-Xbootclasspath/a:" + bootAppendJar,
+ "-Xlog:class+load=info",
"--limit-modules", "java.base",
- "-XX:+TraceClassLoading",
MAIN_CLASS,
- "Test #4", BOOT_APPEND_MODULE_CLASS, "true", "BOOT");
- TestCommon.checkExec(output);
- if (!TestCommon.isUnableToMap(output))
- output.shouldContain("[class,load] sun.nio.cs.ext.MyClass source: shared objects file");
+ "Test #4", BOOT_APPEND_MODULE_CLASS, "true", "BOOT")
+ .assertSilentlyDisabledCDS(out -> {
+ out.shouldHaveExitValue(0)
+ .shouldMatch(".class.load. sun.nio.cs.ext.MyClass source:.*bootAppend.jar");
+ });
}
@@ -229,28 +232,28 @@
public static void testBootAppendAppExcludeModuleClassWithoutAppCDS()
throws Exception {
- CDSOptions opts = (new CDSOptions())
- .addPrefix("-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar,
- "--limit-modules", "java.base")
- .setArchiveName(testArchiveName)
- .addSuffix(MAIN_CLASS, "Test #9", APP_MODULE_CLASS, "true", "BOOT");
-
- CDSTestUtils.runWithArchiveAndCheck(opts);
+ TestCommon.run(
+ "-Xbootclasspath/a:" + bootAppendJar, "-cp", appJar,
+ "-Xlog:class+load=info",
+ "--limit-modules", "java.base",
+ MAIN_CLASS, "Test #9", APP_MODULE_CLASS, "true", "BOOT")
+ .assertSilentlyDisabledCDS(out -> {
+ out.shouldHaveExitValue(0)
+ .shouldMatch(".class.load. com.sun.tools.javac.Main2 source:.*bootAppend.jar");
+ });
}
// Test #10: A shared class in excluded package defined in jimage app module
// - should be loaded from the -Xbootclasspath/a with AppCDS
public static void testBootAppendAppExcludeModuleClassAppCDS() throws Exception {
- OutputAnalyzer output = TestCommon.exec(
- appJar,
- "-Xbootclasspath/a:" + bootAppendJar,
- "-XX:+TraceClassLoading",
+ TestCommon.run(
+ "-cp", appJar, "-Xbootclasspath/a:" + bootAppendJar,
+ "-Xlog:class+load=info",
"--limit-modules", "java.base",
- MAIN_CLASS,
- "Test #10", APP_MODULE_CLASS, "true", "BOOT");
- TestCommon.checkExec(output);
-
- if (!TestCommon.isUnableToMap(output))
- output.shouldContain("[class,load] com.sun.tools.javac.Main2 source: shared objects file");
+ MAIN_CLASS, "Test #10", APP_MODULE_CLASS, "true", "BOOT")
+ .assertSilentlyDisabledCDS(out -> {
+ out.shouldHaveExitValue(0)
+ .shouldMatch(".class.load. com.sun.tools.javac.Main2 source:.*bootAppend.jar");
+ });
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/classpathtests/EmptyClassInBootClassPath.java Tue Apr 17 18:18:53 2018 +0100
@@ -89,13 +89,15 @@
argsList.add("useAppLoader");
opts = new String[argsList.size()];
opts = argsList.toArray(opts);
- TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION);
+ TestCommon.run(opts)
+ .assertSilentlyDisabledCDS(0, EXPECTED_EXCEPTION);
// case 4: load class in bootclasspath using boot loader with '--limit-modules java.base'
argsList.remove(argsList.size() - 1);
argsList.add("useBootLoader");
opts = new String[argsList.size()];
opts = argsList.toArray(opts);
- TestCommon.run(opts).assertNormalExit(EXPECTED_EXCEPTION);
+ TestCommon.run(opts)
+ .assertSilentlyDisabledCDS(0, EXPECTED_EXCEPTION);
}
}
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsHelper.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsHelper.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,11 +65,22 @@
// Make sure we got the expected defining ClassLoader
testLoader(clazz, expectedLoaders[i]);
- // Make sure the class is in the shared space
- if (!wb.isSharedClass(clazz)) {
- throw new RuntimeException(clazz.getName() +
- ".class should be in the shared space. " +
- "loader=" + clazz.getClassLoader() + " module=" + clazz.getModule().getName());
+ // Make sure the class is not in the shared space
+ // because CDS is disabled with --limit-modules during run time.
+ if (excludeModIdx != -1) {
+ if (wb.isSharedClass(clazz)) {
+ throw new RuntimeException(clazz.getName() +
+ ".class should not be in the shared space. " +
+ "loader=" + clazz.getClassLoader() + " module=" + clazz.getModule().getName());
+ }
+ } else {
+ // class should be in the shared space if --limit-modules
+ // isn't specified during run time
+ if (!wb.isSharedClass(clazz)) {
+ throw new RuntimeException(clazz.getName() +
+ ".class should be in the shared space. " +
+ "loader=" + clazz.getClassLoader() + " module=" + clazz.getModule().getName());
+ }
}
}
clazz = null;
--- a/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsTests.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/limitmods/LimitModsTests.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -150,14 +150,14 @@
}
}
}
- output = TestCommon.exec(
- appJar + File.pathSeparator + helperJar,
+ TestCommon.run(
+ "-cp", appJar + File.pathSeparator + helperJar,
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", bootClassPath,
"--limit-modules", limitMods,
"LimitModsHelper",
BOOT_ARCHIVE_CLASS, PLATFORM_ARCHIVE_CLASS, APP_ARCHIVE_CLASS,
- Integer.toString(excludeModIdx)); // last 4 args passed to test
- TestCommon.checkExec(output);
+ Integer.toString(excludeModIdx)) // last 4 args passed to test
+ .assertSilentlyDisabledCDS(0);
limitMods = null;
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddModules.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ * jdk.jartool/sun.tools.jar
+ * jdk.jlink
+ * @run main AddModules
+ * @summary sanity test the --add-modules option
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class AddModules {
+
+ private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+ private static final String TEST_SRC = System.getProperty("test.src");
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path MODS_DIR = Paths.get("mods");
+
+ // the module name of the test module
+ private static final String MAIN_MODULE1 = "com.greetings";
+ private static final String MAIN_MODULE2 = "com.hello";
+ private static final String SUB_MODULE = "org.astro";
+
+ // the module main class
+ private static final String MAIN_CLASS1 = "com.greetings.Main";
+ private static final String MAIN_CLASS2 = "com.hello.Main";
+ private static final String APP_CLASS = "org.astro.World";
+
+ private static Path moduleDir = null;
+ private static Path subJar = null;
+ private static Path mainJar1 = null;
+ private static Path mainJar2 = null;
+
+ public static void buildTestModule() throws Exception {
+
+ // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(SUB_MODULE),
+ MODS_DIR.resolve(SUB_MODULE),
+ null);
+
+ // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE1),
+ MODS_DIR.resolve(MAIN_MODULE1),
+ MODS_DIR.toString());
+
+ JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE2),
+ MODS_DIR.resolve(MAIN_MODULE2),
+ MODS_DIR.toString());
+
+ moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+ subJar = moduleDir.resolve(SUB_MODULE + ".jar");
+ String classes = MODS_DIR.resolve(SUB_MODULE).toString();
+ JarBuilder.createModularJar(subJar.toString(), classes, null);
+
+ mainJar1 = moduleDir.resolve(MAIN_MODULE1 + ".jar");
+ classes = MODS_DIR.resolve(MAIN_MODULE1).toString();
+ JarBuilder.createModularJar(mainJar1.toString(), classes, MAIN_CLASS1);
+
+ mainJar2 = moduleDir.resolve(MAIN_MODULE2 + ".jar");
+ classes = MODS_DIR.resolve(MAIN_MODULE2).toString();
+ JarBuilder.createModularJar(mainJar2.toString(), classes, MAIN_CLASS2);
+
+ }
+
+ public static void main(String... args) throws Exception {
+ // compile the modules and create the modular jar files
+ buildTestModule();
+ String appClasses[] = {MAIN_CLASS1, MAIN_CLASS2, APP_CLASS};
+ // create an archive with the classes in the modules built in the
+ // previous step
+ OutputAnalyzer output = TestCommon.createArchive(
+ null, appClasses,
+ "--module-path", moduleDir.toString(),
+ "--add-modules",
+ MAIN_MODULE1 + "," + MAIN_MODULE2);
+ TestCommon.checkDump(output);
+ String prefix[] = {"-cp", "\"\"", "-Xlog:class+load=trace"};
+
+ // run the com.greetings module with the archive with the --module-path
+ // the same as the one during dump time.
+ // The classes should be loaded from the archive.
+ TestCommon.runWithModules(prefix,
+ null, // --upgrade-module-path
+ moduleDir.toString(), // --module-path
+ MAIN_MODULE1) // -m
+ .assertNormalExit(out -> {
+ out.shouldContain("[class,load] com.greetings.Main source: shared objects file")
+ .shouldContain("[class,load] org.astro.World source: shared objects file");
+ });
+
+ // run the com.hello module with the archive with the --module-path
+ // the same as the one during dump time.
+ // The classes should be loaded from the archive.
+ TestCommon.runWithModules(prefix,
+ null, // --upgrade-module-path
+ moduleDir.toString(), // --module-path
+ MAIN_MODULE2) // -m
+ .assertNormalExit(out -> {
+ out.shouldContain("[class,load] com.hello.Main source: shared objects file")
+ .shouldContain("[class,load] org.astro.World source: shared objects file");
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddOpens.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ * jdk.jartool/sun.tools.jar
+ * jdk.jlink
+ * @run main AddOpens
+ * @summary sanity test the --add-opens option
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class AddOpens {
+
+ private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+ private static final String TEST_SRC = System.getProperty("test.src");
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path MODS_DIR = Paths.get("mods");
+
+ // the module name of the test module
+ private static final String TEST_MODULE1 = "com.simple";
+
+ // the module main class
+ private static final String MAIN_CLASS = "com.simple.Main";
+
+ private static Path moduleDir = null;
+ private static Path moduleDir2 = null;
+ private static Path destJar = null;
+
+ public static void buildTestModule() throws Exception {
+
+ // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
+ MODS_DIR.resolve(TEST_MODULE1),
+ MODS_DIR.toString());
+
+ moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+ moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
+
+ Path srcJar = moduleDir.resolve(TEST_MODULE1 + ".jar");
+ destJar = moduleDir2.resolve(TEST_MODULE1 + ".jar");
+ String classes = MODS_DIR.resolve(TEST_MODULE1).toString();
+ JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS);
+ Files.copy(srcJar, destJar);
+
+ }
+
+ public static void main(String... args) throws Exception {
+ // compile the modules and create the modular jar files
+ buildTestModule();
+ String appClasses[] = {MAIN_CLASS};
+ // create an archive with both -cp and --module-path in the command line.
+ // Only the class in the modular jar in the --module-path will be archived;
+ // the class in the modular jar in the -cp won't be archived.
+ OutputAnalyzer output = TestCommon.createArchive(
+ destJar.toString(), appClasses,
+ "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit",
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1);
+ TestCommon.checkDump(output);
+
+ // run with the archive using the same command line as in dump time
+ // plus the "--add-opens java.base/java.lang=com.simple" option.
+ // The main class should be loaded from the archive.
+ // The setaccessible(true) on the ClassLoader.defineClass method should
+ // be successful.
+ TestCommon.run( "-Xlog:class+load=trace",
+ "-cp", destJar.toString(),
+ "--add-opens", "java.base/java.lang=" + TEST_MODULE1,
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1, "with_add_opens")
+ .assertNormalExit(
+ "[class,load] com.simple.Main source: shared objects file",
+ "method.setAccessible succeeded!");
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/AddReads.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ * jdk.jartool/sun.tools.jar
+ * jdk.jlink
+ * @run main AddReads
+ * @summary sanity test the --add-reads option
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.Asserts;
+
+public class AddReads {
+
+ private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+ private static final String TEST_SRC = System.getProperty("test.src");
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path MODS_DIR = Paths.get("mods");
+
+ // the module name of the test module
+ private static final String MAIN_MODULE = "com.norequires";
+ private static final String SUB_MODULE = "org.astro";
+
+ // the module main class
+ private static final String MAIN_CLASS = "com.norequires.Main";
+ private static final String APP_CLASS = "org.astro.World";
+
+ private static Path moduleDir = null;
+ private static Path subJar = null;
+ private static Path mainJar = null;
+
+ public static void buildTestModule() throws Exception {
+
+ // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(SUB_MODULE),
+ MODS_DIR.resolve(SUB_MODULE),
+ null);
+
+ Asserts.assertTrue(CompilerUtils
+ .compile(SRC_DIR.resolve(MAIN_MODULE),
+ MODS_DIR.resolve(MAIN_MODULE),
+ "-cp", MODS_DIR.resolve(SUB_MODULE).toString(),
+ "--add-reads", "com.norequires=ALL-UNNAMED"));
+
+ moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+ subJar = moduleDir.resolve(SUB_MODULE + ".jar");
+ String classes = MODS_DIR.resolve(SUB_MODULE).toString();
+ JarBuilder.createModularJar(subJar.toString(), classes, null);
+
+ mainJar = moduleDir.resolve(MAIN_MODULE + ".jar");
+ classes = MODS_DIR.resolve(MAIN_MODULE).toString();
+ JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS);
+ }
+
+ public static void main(String... args) throws Exception {
+ // compile the modules and create the modular jar files
+ buildTestModule();
+ String appClasses[] = {MAIN_CLASS, APP_CLASS};
+ // create an archive with the classes in the modules built in the
+ // previous step
+ OutputAnalyzer output = TestCommon.createArchive(
+ null, appClasses,
+ "--module-path", moduleDir.toString(),
+ "--add-modules", SUB_MODULE,
+ "--add-reads", "com.norequires=org.astro",
+ "-m", MAIN_MODULE);
+ TestCommon.checkDump(output);
+ String prefix[] = {"-cp", "\"\"", "-Xlog:class+load=trace",
+ "--add-modules", SUB_MODULE,
+ "--add-reads", "com.norequires=org.astro"};
+
+ // run the com.norequires module with the archive with the same args
+ // used during dump time.
+ // The classes should be loaded from the archive.
+ TestCommon.runWithModules(prefix,
+ null, // --upgrade-module-path
+ moduleDir.toString(), // --module-path
+ MAIN_MODULE) // -m
+ .assertNormalExit(out -> {
+ out.shouldContain("[class,load] com.norequires.Main source: shared objects file")
+ .shouldContain("[class,load] org.astro.World source: shared objects file");
+ });
+
+ // create an archive with -cp pointing to the jar file containing the
+ // org.astro module and --module-path pointing to the main module
+ output = TestCommon.createArchive(
+ subJar.toString(), appClasses,
+ "--module-path", moduleDir.toString(),
+ "--add-modules", SUB_MODULE,
+ "--add-reads", "com.norequires=org.astro",
+ "-m", MAIN_MODULE);
+ TestCommon.checkDump(output);
+ // run the com.norequires module with the archive with the sub-module
+ // in the -cp and with -add-reads=com.norequires=ALL-UNNAMED
+ // The main class should be loaded from the archive.
+ // The org.astro.World should be loaded from the jar.
+ String prefix2[] = {"-cp", subJar.toString(), "-Xlog:class+load=trace",
+ "--add-reads", "com.norequires=ALL-UNNAMED"};
+ TestCommon.runWithModules(prefix2,
+ null, // --upgrade-module-path
+ moduleDir.toString(), // --module-path
+ MAIN_MODULE) // -m
+ .assertNormalExit(out -> {
+ out.shouldContain("[class,load] com.norequires.Main source: shared objects file")
+ .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar");
+ });
+
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ExportModule.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ * jdk.jartool/sun.tools.jar
+ * jdk.jlink
+ * @run main ExportModule
+ * @summary Tests involve exporting a module from the module path to a jar in the -cp.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.compiler.CompilerUtils;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.Asserts;
+
+public class ExportModule {
+
+ private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+ private static final String TEST_SRC = System.getProperty("test.src");
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path MODS_DIR = Paths.get("mods");
+
+ // the module name of the test module
+ private static final String TEST_MODULE1 = "com.greetings";
+ private static final String TEST_MODULE2 = "org.astro";
+
+ // unnamed module package name
+ private static final String PKG_NAME = "com.nomodule";
+
+ // the module main class
+ private static final String MAIN_CLASS = "com.greetings.Main";
+ private static final String APP_CLASS = "org.astro.World";
+
+ // unnamed module main class
+ private static final String UNNAMED_MAIN = "com.nomodule.Main";
+
+ private static Path moduleDir = null;
+ private static Path moduleDir2 = null;
+ private static Path appJar = null;
+ private static Path appJar2 = null;
+
+ public static void buildTestModule() throws Exception {
+
+ // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE2),
+ MODS_DIR.resolve(TEST_MODULE2),
+ null);
+
+ // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
+ MODS_DIR.resolve(TEST_MODULE1),
+ MODS_DIR.toString());
+
+ moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+ Path jar = moduleDir.resolve(TEST_MODULE2 + ".jar");
+ String classes = MODS_DIR.resolve(TEST_MODULE2).toString();
+ JarBuilder.createModularJar(jar.toString(), classes, null);
+
+ moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
+ appJar = moduleDir2.resolve(TEST_MODULE1 + ".jar");
+ classes = MODS_DIR.resolve(TEST_MODULE1).toString();
+ JarBuilder.createModularJar(appJar.toString(), classes, MAIN_CLASS);
+
+ // build a non-modular jar containing the main class which
+ // requires the org.astro package
+ boolean compiled
+ = CompilerUtils.compile(SRC_DIR.resolve(PKG_NAME),
+ MODS_DIR.resolve(PKG_NAME),
+ "--module-path", MODS_DIR.toString(),
+ "--add-modules", TEST_MODULE2,
+ "--add-exports", "org.astro/org.astro=ALL-UNNAMED");
+ Asserts.assertTrue(compiled, "test package did not compile");
+
+ appJar2 = moduleDir2.resolve(PKG_NAME + ".jar");
+ classes = MODS_DIR.resolve(PKG_NAME).toString();
+ JarBuilder.createModularJar(appJar2.toString(), classes, null);
+ }
+
+ public static void main(String... args) throws Exception {
+ // compile the modules and create the modular jar files
+ buildTestModule();
+ String appClasses[] = {MAIN_CLASS, APP_CLASS};
+ // create an archive with the class in the org.astro module built in the
+ // previous step and the main class from the modular jar in the -cp
+ // note: the main class is in the modular jar in the -cp which requires
+ // the module in the --module-path
+ OutputAnalyzer output = TestCommon.createArchive(
+ appJar.toString(), appClasses,
+ "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit",
+ "--module-path", moduleDir.toString(),
+ "--add-modules", TEST_MODULE2, MAIN_CLASS);
+ TestCommon.checkDump(output);
+
+ // run it using the archive
+ // both the main class and the class from the org.astro module should
+ // be loaded from the archive
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", appJar.toString(),
+ "--module-path", moduleDir.toString(),
+ "--add-modules", TEST_MODULE2, MAIN_CLASS)
+ .assertNormalExit(
+ "[class,load] org.astro.World source: shared objects file",
+ "[class,load] com.greetings.Main source: shared objects file");
+
+ String appClasses2[] = {UNNAMED_MAIN, APP_CLASS};
+ // create an archive with the main class from a non-modular jar in the
+ // -cp and the class from the org.astro module
+ // note: the org.astro package needs to be exported to "ALL-UNNAMED"
+ // module since the jar in the -cp is a non-modular jar and thus it is
+ // unnmaed.
+ output = TestCommon.createArchive(
+ appJar2.toString(), appClasses2,
+ "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit",
+ "--module-path", moduleDir.toString(),
+ "--add-modules", TEST_MODULE2,
+ "--add-exports", "org.astro/org.astro=ALL-UNNAMED",
+ UNNAMED_MAIN);
+ TestCommon.checkDump(output);
+
+ // both the main class and the class from the org.astro module should
+ // be loaded from the archive
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", appJar2.toString(),
+ "--module-path", moduleDir.toString(),
+ "--add-modules", TEST_MODULE2,
+ "--add-exports", "org.astro/org.astro=ALL-UNNAMED",
+ UNNAMED_MAIN)
+ .assertNormalExit(
+ "[class,load] org.astro.World source: shared objects file",
+ "[class,load] com.nomodule.Main source: shared objects file");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/JvmtiAddPath.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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
+ * @summary JvmtiEnv::AddToBootstrapClassLoaderSearch and JvmtiEnv::AddToSystemClassLoaderSearch should disable AppCDS
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules java.base/jdk.internal.misc
+ * java.management
+ * jdk.jartool/sun.tools.jar
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ * @compile ../../test-classes/JvmtiApp.java
+ * @run main JvmtiAddPath
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import jdk.test.lib.process.OutputAnalyzer;
+import sun.hotspot.WhiteBox;
+
+public class JvmtiAddPath {
+ static String use_whitebox_jar;
+ static String[] no_extra_matches = {};
+ static String[] check_appcds_enabled = {
+ "[class,load] ExtraClass source: shared object"
+ };
+ static String[] check_appcds_disabled = {
+ "[class,load] ExtraClass source: file:"
+ };
+
+ private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+ private static final String TEST_SRC = System.getProperty("test.src");
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path MODS_DIR = Paths.get("mods");
+
+ // the module name of the test module
+ private static final String TEST_MODULE1 = "com.simple";
+
+ // the module main class
+ private static final String MAIN_CLASS = "com.simple.Main";
+
+ private static Path moduleDir = null;
+ private static Path mainJar = null;
+
+ public static void buildTestModule() throws Exception {
+
+ // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
+ MODS_DIR.resolve(TEST_MODULE1),
+ MODS_DIR.toString());
+
+ moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+
+ mainJar = moduleDir.resolve(TEST_MODULE1 + ".jar");
+ String classes = MODS_DIR.resolve(TEST_MODULE1).toString();
+ JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS);
+ }
+
+ static void run(String cp, String... args) throws Exception {
+ run(no_extra_matches, cp, args);
+ }
+
+ static void run(String[] extra_matches, String cp, String... args) throws Exception {
+ String[] opts = {"-cp", cp, "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", use_whitebox_jar};
+ opts = TestCommon.concat(opts, args);
+ TestCommon.run(opts).assertNormalExit(extra_matches);
+ }
+
+ public static void main(String[] args) throws Exception {
+ buildTestModule();
+ JarBuilder.build("jvmti_app", "JvmtiApp", "ExtraClass");
+ JarBuilder.build(true, "WhiteBox", "sun/hotspot/WhiteBox");
+
+ // In all the test cases below, appJar does not contain Hello.class. Instead, we
+ // append JAR file(s) that contain Hello.class to the boot classpath, the app
+ // classpath, or both, and verify that Hello.class is loaded by the expected ClassLoader.
+ String appJar = TestCommon.getTestJar("jvmti_app.jar"); // contains JvmtiApp.class
+ String addappJar = mainJar.toString(); // contains Main.class
+ String addbootJar = mainJar.toString(); // contains Main.class
+ String twoAppJars = appJar + File.pathSeparator + addappJar;
+ String modulePath = "--module-path=" + moduleDir.toString();
+ String wbJar = TestCommon.getTestJar("WhiteBox.jar");
+ use_whitebox_jar = "-Xbootclasspath/a:" + wbJar;
+
+ OutputAnalyzer output = TestCommon.createArchive(
+ appJar,
+ TestCommon.list("JvmtiApp", "ExtraClass", MAIN_CLASS),
+ use_whitebox_jar,
+ "-Xlog:class+load=trace",
+ modulePath);
+ TestCommon.checkDump(output);
+
+ System.out.println("Test case 1: not adding module path - Hello.class should not be found");
+ run(check_appcds_enabled, appJar,
+ "-Xlog:class+load", "JvmtiApp", "noadd", MAIN_CLASS); // appcds should be enabled
+
+ System.out.println("Test case 2: add to boot classpath only - should find Hello.class in boot loader");
+ run(check_appcds_disabled, appJar,
+ "-Xlog:class+load=trace",
+ modulePath,
+ "JvmtiApp", "bootonly", addbootJar, MAIN_CLASS); // appcds should be disabled
+
+ System.out.println("Test case 3: add to app classpath only - should find Hello.class in app loader");
+ run(appJar, modulePath,
+ "JvmtiApp", "apponly", addappJar, MAIN_CLASS);
+
+ System.out.println("Test case 4: add to boot and app paths - should find Hello.class in boot loader");
+ run(appJar, modulePath,
+ "JvmtiApp", "appandboot", addbootJar, addappJar, MAIN_CLASS);
+
+ System.out.println("Test case 5: add to app using -cp, but add to boot using JVMTI - should find Hello.class in boot loader");
+ run(appJar, modulePath,
+ "JvmtiApp", "bootonly", addappJar, MAIN_CLASS);
+
+ System.out.println("Test case 6: add to app using AppCDS, but add to boot using JVMTI - should find Hello.class in boot loader");
+ output = TestCommon.createArchive(
+ appJar, TestCommon.list("JvmtiApp", "ExtraClass"),
+ use_whitebox_jar,
+ "-Xlog:class+load=trace",
+ modulePath);
+ TestCommon.checkDump(output);
+ run(twoAppJars, modulePath,
+ "JvmtiApp", "bootonly", addappJar, MAIN_CLASS);
+
+ System.out.println("Test case 7: add to app using AppCDS, no JVMTI calls - should find Hello.class in app loader");
+ run(twoAppJars, modulePath,
+ "JvmtiApp", "noadd-appcds", MAIN_CLASS);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/MainModuleOnly.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ * jdk.jartool/sun.tools.jar
+ * jdk.jlink
+ * @run main MainModuleOnly
+ * @summary Test some scenarios with a main modular jar specified in the --module-path and -cp options in the command line.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class MainModuleOnly {
+
+ private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+ private static final String TEST_SRC = System.getProperty("test.src");
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path MODS_DIR = Paths.get("mods");
+
+ // the module name of the test module
+ private static final String TEST_MODULE1 = "com.simple";
+
+ // the module main class
+ private static final String MAIN_CLASS = "com.simple.Main";
+
+ private static Path moduleDir = null;
+ private static Path moduleDir2 = null;
+ private static Path destJar = null;
+
+ public static void buildTestModule() throws Exception {
+
+ // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE1),
+ MODS_DIR.resolve(TEST_MODULE1),
+ MODS_DIR.toString());
+
+
+ moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+ moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
+
+ Path srcJar = moduleDir.resolve(TEST_MODULE1 + ".jar");
+ destJar = moduleDir2.resolve(TEST_MODULE1 + ".jar");
+ String classes = MODS_DIR.resolve(TEST_MODULE1).toString();
+ JarBuilder.createModularJar(srcJar.toString(), classes, MAIN_CLASS);
+ Files.copy(srcJar, destJar);
+
+ }
+
+ public static void main(String... args) throws Exception {
+ // compile the modules and create the modular jar files
+ buildTestModule();
+ String appClasses[] = {MAIN_CLASS};
+ // create an archive with both -cp and --module-path in the command line.
+ // Only the class in the modular jar in the --module-path will be archived;
+ // the class in the modular jar in the -cp won't be archived.
+ OutputAnalyzer output = TestCommon.createArchive(
+ destJar.toString(), appClasses,
+ "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit",
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1);
+ TestCommon.checkDump(output);
+
+ // run with the archive using the same command line as in dump time.
+ // The main class should be loaded from the archive.
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", destJar.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertNormalExit("[class,load] com.simple.Main source: shared objects file");
+
+ // run with the archive with the main class name inserted before the -m.
+ // The main class name will be picked up before the module name. So the
+ // main class should be loaded from the jar in the -cp.
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", destJar.toString(),
+ "--module-path", moduleDir.toString(),
+ MAIN_CLASS, "-m", TEST_MODULE1)
+ .assertNormalExit(out ->
+ out.shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar"));
+
+ // run with the archive with exploded module. Since during dump time, we
+ // only archive classes from the modular jar in the --module-path, the
+ // main class should be loaded from the exploded module directory.
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", destJar.toString(),
+ "--module-path", MODS_DIR.toString(),
+ "-m", TEST_MODULE1 + "/" + MAIN_CLASS)
+ .assertNormalExit(out -> {
+ out.shouldMatch(".class.load. com.simple.Main source:.*com.simple")
+ .shouldContain(MODS_DIR.toString());
+ });
+
+ // run with the archive with the --upgrade-module-path option.
+ // CDS will be disabled with this options and the main class will be
+ // loaded from the modular jar.
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", destJar.toString(),
+ "--upgrade-module-path", moduleDir.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertSilentlyDisabledCDS(out -> {
+ out.shouldHaveExitValue(0)
+ .shouldMatch("CDS is disabled when the.*option is specified")
+ .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar");
+ });
+ // run with the archive with the --limit-modules option.
+ // CDS will be disabled with this options and the main class will be
+ // loaded from the modular jar.
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", destJar.toString(),
+ "--limit-modules", "java.base," + TEST_MODULE1,
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertSilentlyDisabledCDS(out -> {
+ out.shouldHaveExitValue(0)
+ .shouldMatch("CDS is disabled when the.*option is specified")
+ .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar");
+ });
+ // run with the archive with the --patch-module option.
+ // CDS will be disabled with this options and the main class will be
+ // loaded from the modular jar.
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", destJar.toString(),
+ "--patch-module", TEST_MODULE1 + "=" + MODS_DIR.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertSilentlyDisabledCDS(out -> {
+ out.shouldHaveExitValue(0)
+ .shouldMatch("CDS is disabled when the.*option is specified")
+ .shouldMatch(".class.load. com.simple.Main source:.*com.simple.jar");
+ });
+ // modify the timestamp of the jar file
+ (new File(destJar.toString())).setLastModified(System.currentTimeMillis() + 2000);
+ // run with the archive and the jar with modified timestamp.
+ // It should fail due to timestamp of the jar doesn't match the one
+ // used during dump time.
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", destJar.toString(),
+ "--module-path", moduleDir.toString(),
+ "-m", TEST_MODULE1)
+ .assertAbnormalExit(
+ "A jar/jimage file is not the one used while building the shared archive file:");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/ModulePathAndCP.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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
+ * @requires vm.cds
+ * @library /test/jdk/lib/testlibrary /test/lib /test/hotspot/jtreg/runtime/appcds
+ * @modules jdk.compiler
+ * jdk.jartool/sun.tools.jar
+ * jdk.jlink
+ * @run main ModulePathAndCP
+ * @summary 2 sets of tests: one with only --module-path in the command line;
+ * another with both -cp and --module-path in the command line.
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class ModulePathAndCP {
+
+ private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
+
+ private static final String TEST_SRC = System.getProperty("test.src");
+
+ private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
+ private static final Path MODS_DIR = Paths.get("mods");
+
+ // the module name of the test module
+ private static final String MAIN_MODULE = "com.greetings";
+ private static final String APP_MODULE = "org.astro";
+
+ // the module main class
+ private static final String MAIN_CLASS = "com.greetings.Main";
+ private static final String APP_CLASS = "org.astro.World";
+
+ private static Path moduleDir = null;
+ private static Path moduleDir2 = null;
+ private static Path subJar = null;
+ private static Path mainJar = null;
+ private static Path destJar = null;
+
+ public static void buildTestModule() throws Exception {
+
+ // javac -d mods/$TESTMODULE src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(APP_MODULE),
+ MODS_DIR.resolve(APP_MODULE),
+ null);
+
+ // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/**
+ JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE),
+ MODS_DIR.resolve(MAIN_MODULE),
+ MODS_DIR.toString());
+
+ moduleDir = Files.createTempDirectory(USER_DIR, "mlib");
+ moduleDir2 = Files.createTempDirectory(USER_DIR, "mlib2");
+ subJar = moduleDir.resolve(APP_MODULE + ".jar");
+ destJar = moduleDir2.resolve(APP_MODULE + ".jar");
+ String classes = MODS_DIR.resolve(APP_MODULE).toString();
+ JarBuilder.createModularJar(subJar.toString(), classes, null);
+ Files.copy(subJar, destJar);
+
+ mainJar = moduleDir.resolve(MAIN_MODULE + ".jar");
+ Path mainJar2 = moduleDir2.resolve(MAIN_MODULE + ".jar");
+ classes = MODS_DIR.resolve(MAIN_MODULE).toString();
+ JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS);
+ Files.copy(mainJar, mainJar2);
+
+ }
+
+ public static void main(String... args) throws Exception {
+ // compile the modules and create the modular jar files
+ buildTestModule();
+ String appClasses[] = {MAIN_CLASS, APP_CLASS};
+ // create an archive with the classes in the modules built in the
+ // previous step
+ OutputAnalyzer output = TestCommon.createArchive(
+ null, appClasses,
+ "--module-path", moduleDir.toString(),
+ "-m", MAIN_MODULE);
+ TestCommon.checkDump(output);
+ String prefix[] = {"-cp", "\"\"", "-Xlog:class+load=trace"};
+
+ // run with the archive with the --module-path the same as the one during
+ // dump time. The classes should be loaded from the archive.
+ TestCommon.runWithModules(prefix,
+ null, // --upgrade-module-path
+ moduleDir.toString(), // --module-path
+ MAIN_MODULE) // -m
+ .assertNormalExit(out -> {
+ out.shouldContain("[class,load] com.greetings.Main source: shared objects file")
+ .shouldContain("[class,load] org.astro.World source: shared objects file");
+ });
+
+ // run with the archive with the --module-path different from the one during
+ // dump time. The classes should be loaded from the jar files.
+ TestCommon.runWithModules(prefix,
+ null, // --upgrade-module-path
+ moduleDir2.toString(), // --module-path
+ MAIN_MODULE) // -m
+ .assertNormalExit(out -> {
+ out.shouldMatch(".class.load. com.greetings.Main source:.*com.greetings.jar")
+ .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar");
+ });
+
+ // create an archive with modular jar files in both -cp and --module-path
+ String jars = subJar.toString() + System.getProperty("path.separator") +
+ mainJar.toString();
+ output = TestCommon.createArchive( jars, appClasses,
+ "-Xlog:class+load=trace", "-XX:+PrintSystemDictionaryAtExit",
+ "--module-path", moduleDir.toString(),
+ "-m", MAIN_MODULE);
+ TestCommon.checkDump(output);
+
+ // run with archive with the main class name specified before
+ // the module name with the -m option. Since the -m option was specified
+ // during dump time, the classes in the jar files after the -cp won't be
+ // archived. Therefore, the classes won't be loaded from the archive but
+ // will be loaded from the jar files.
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", jars,
+ "--module-path", moduleDir.toString(),
+ MAIN_CLASS, "-m", MAIN_MODULE)
+ .assertNormalExit(out -> {
+ out.shouldMatch(".class.load. com.greetings.Main source:.*com.greetings.jar")
+ .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar");
+ });
+
+ // similar to the above case but without the main class name. The classes
+ // should be loaded from the archive.
+ TestCommon.run("-Xlog:class+load=trace",
+ "-cp", jars,
+ "--module-path", moduleDir.toString(),
+ "-m", MAIN_MODULE)
+ .assertNormalExit(
+ "[class,load] com.greetings.Main source: shared objects file",
+ "[class,load] org.astro.World source: shared objects file");
+
+ // create an archive with two modular jars in the --module-path
+ output = TestCommon.createArchive(
+ null, appClasses,
+ "--module-path", jars,
+ "-m", MAIN_MODULE);
+ TestCommon.checkDump(output);
+
+ // run with the above archive but with the modular jar containing the
+ // org.astro module in a different location.
+ // The org.astro.World class should be loaded from the jar.
+ // The Main class should still be loaded from the archive.
+ jars = destJar.toString() + System.getProperty("path.separator") +
+ mainJar.toString();
+ TestCommon.runWithModules(prefix,
+ null, // --upgrade-module-path
+ jars, // --module-path
+ MAIN_MODULE) // -m
+ .assertNormalExit(out -> {
+ out.shouldContain("[class,load] com.greetings.Main source: shared objects file")
+ .shouldMatch(".class.load. org.astro.World source:.*org.astro.jar");
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.greetings/com/greetings/Main.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 com.greetings;
+import org.astro.World;
+public class Main {
+ public static void main(String[] args) {
+ System.out.format("Greetings %s!\n", World.name());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.greetings/module-info.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ *
+ */
+
+module com.greetings {
+ requires org.astro;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.hello/com/hello/Main.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 com.hello;
+import org.astro.World;
+public class Main {
+ public static void main(String[] args) {
+ System.out.format("Hello %s!\n", World.name());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.hello/module-info.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ *
+ */
+
+module com.hello {
+ requires org.astro;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.nomodule/com/nomodule/Main.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 com.nomodule;
+import org.astro.World;
+public class Main {
+ public static void main(String[] args) {
+ System.out.format("Greetings %s!\n", World.name());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.norequires/com/norequires/Main.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 com.norequires;
+import org.astro.World;
+public class Main {
+ public static void main(String[] args) {
+ System.out.format("Hello %s!\n", World.name());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.norequires/module-info.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ *
+ */
+
+module com.norequires { }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.simple/com/simple/Main.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 com.simple;
+
+import java.lang.reflect.Method;
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ System.out.println("Hello World!");
+ if (args.length > 0 && args[0].equals("with_add_opens")) {
+ Method method = ClassLoader.class.getDeclaredMethod("defineClass",
+ byte[].class, int.class, int.class);
+ method.setAccessible(true);
+ System.out.println("method.setAccessible succeeded!");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/com.simple/module-info.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ *
+ */
+
+module com.simple {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/org.astro/module-info.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ *
+ */
+
+module org.astro {
+ exports org.astro;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/jigsaw/modulepath/src/org.astro/org/astro/World.java Tue Apr 17 18:18:53 2018 +0100
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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 org.astro;
+public class World {
+ public static String name() {
+ return "world";
+ }
+}
--- a/test/hotspot/jtreg/runtime/appcds/test-classes/JvmtiApp.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/appcds/test-classes/JvmtiApp.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* 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,9 +25,9 @@
import sun.hotspot.WhiteBox;
public class JvmtiApp {
- static Class forname() {
+ static Class forname(String cn) {
try {
- return Class.forName("Hello");
+ return Class.forName(cn);
} catch (Throwable t) {
return null;
}
@@ -40,9 +40,14 @@
// See ../JvmtiAddPath.java for how the classpaths are configured.
public static void main(String args[]) {
+ String cn = "Hello";
+ if (args.length >= 3) {
+ cn = args[args.length - 1];
+ }
+
if (args[0].equals("noadd")) {
- if (forname() != null) {
- failed("Hello class was loaded unexpectedly");
+ if (forname(cn) != null) {
+ failed(cn + " class was loaded unexpectedly");
}
// We use -verbose:class to verify that Extra.class IS loaded by AppCDS if
// the boot classpath HAS NOT been appended.
@@ -54,39 +59,41 @@
if (args[0].equals("bootonly")) {
wb.addToBootstrapClassLoaderSearch(args[1]);
- Class cls = forname();
+ Class cls = forname(cn);
if (cls == null) {
- failed("Cannot find Hello class");
+ failed("Cannot find " + cn + " class");
}
if (cls.getClassLoader() != null) {
failed("Hello class not loaded by boot classloader");
}
} else if (args[0].equals("apponly")) {
wb.addToSystemClassLoaderSearch(args[1]);
- Class cls = forname();
+ Class cls = forname(cn);
if (cls == null) {
- failed("Cannot find Hello class");
+ failed("Cannot find " + cn + " class");
}
if (cls.getClassLoader() != JvmtiApp.class.getClassLoader()) {
- failed("Hello class not loaded by app classloader");
+ failed(cn + " class not loaded by app classloader");
}
} else if (args[0].equals("noadd-appcds")) {
- Class cls = forname();
+ cn = (args.length == 1) ? "Hello" : args[1];
+ Class cls = forname(cn);
if (cls == null) {
- failed("Cannot find Hello class");
+ failed("Cannot find " + cn + " class");
}
if (cls.getClassLoader() != JvmtiApp.class.getClassLoader()) {
- failed("Hello class not loaded by app classloader");
+ failed(cn + " class not loaded by app classloader");
}
} else if (args[0].equals("appandboot")) {
wb.addToBootstrapClassLoaderSearch(args[1]);
wb.addToSystemClassLoaderSearch(args[2]);
- Class cls = forname();
+ cn = (args.length == 3) ? "Hello" : args[3];
+ Class cls = forname(cn);
if (cls == null) {
- failed("Cannot find Hello class");
+ failed("Cannot find " + cn + " class");
}
if (cls.getClassLoader() != null) {
- failed("Hello class not loaded by boot classloader");
+ failed(cn + " class not loaded by boot classloader");
}
} else {
failed("unknown option " + args[0]);
@@ -102,4 +109,4 @@
class ExtraClass {
static void doit() {}
-}
\ No newline at end of file
+}
--- a/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/runtime/modules/PatchModule/PatchModuleCDS.java Tue Apr 17 18:18:53 2018 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,7 +50,8 @@
"-Xlog:class+path=info",
"-version");
new OutputAnalyzer(pb.start())
- .shouldContain("ro space:"); // Make sure archive got created.
+ // --patch-module is not supported during CDS dumping
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
// Case 2: Test that directory in --patch-module is supported for CDS dumping
// Create a class file in the module java.base.
@@ -73,7 +74,8 @@
"-Xlog:class+path=info",
"-version");
new OutputAnalyzer(pb.start())
- .shouldContain("ro space:"); // Make sure archive got created.
+ // --patch-module is not supported during CDS dumping
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
// Case 3a: Test CDS dumping with jar file in --patch-module
BasicJarBuilder.build("javanaming", "javax/naming/spi/NamingManager");
@@ -87,7 +89,8 @@
"-Xlog:class+path=info",
"PatchModuleMain", "javax.naming.spi.NamingManager");
new OutputAnalyzer(pb.start())
- .shouldContain("ro space:"); // Make sure archive got created.
+ // --patch-module is not supported during CDS dumping
+ .shouldContain("Cannot use the following option when dumping the shared archive: --patch-module");
// Case 3b: Test CDS run with jar file in --patch-module
pb = ProcessTools.createJavaProcessBuilder(
--- a/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c Tue Apr 17 08:54:17 2018 -0700
+++ b/test/hotspot/jtreg/serviceability/jvmti/FieldAccessWatch/libFieldAccessWatch.c Tue Apr 17 18:18:53 2018 +0100
@@ -35,7 +35,6 @@
static jvmtiEnv *jvmti = NULL;
// valid while a test is executed
-static JNIEnv *javaEnv = NULL;
static jobject testResultObject = NULL;
static jclass testResultClass = NULL;
@@ -46,7 +45,8 @@
// logs the notification and updates currentTestResult
-static void handleNotification(jmethodID method,
+static void handleNotification(JNIEnv *jni_env,
+ jmethodID method,
jfieldID field,
jclass field_klass,
int modified,
@@ -92,21 +92,21 @@
csig, mname, mgensig, modified ? "modified" : "accessed", name, (int)location);
// set TestResult
- if (javaEnv != NULL && testResultObject != NULL && testResultClass != NULL) {
+ if (testResultObject != NULL && testResultClass != NULL) {
jfieldID fieldID;
// field names in TestResult are "<field_name>_access"/"<field_name>_modify"
char *fieldName = (char *)malloc(strlen(name) + 16);
strcpy(fieldName, name);
strcat(fieldName, modified ? "_modify" : "_access");
- fieldID = (*javaEnv)->GetFieldID(javaEnv, testResultClass, fieldName, "Z");
+ fieldID = (*jni_env)->GetFieldID(jni_env, testResultClass, fieldName, "Z");
if (fieldID != NULL) {
- (*javaEnv)->SetBooleanField(javaEnv, testResultObject, fieldID, JNI_TRUE);
+ (*jni_env)->SetBooleanField(jni_env, testResultObject, fieldID, JNI_TRUE);
} else {
// the field is not interesting for the test
}
// clear any possible exception
- (*javaEnv)->ExceptionClear(javaEnv);
+ (*jni_env)->ExceptionClear(jni_env);
free(fieldName);
}
@@ -179,7 +179,7 @@
jobject object,
jfieldID field)
{
- handleNotification(method, field, field_klass, 0, location);
+ handleNotification(jni_env, method, field, field_klass, 0, location);
}
@@ -195,7 +195,7 @@
char signature_type,
jvalue new_value)
{
- handleNotification(method, field, field_klass, 1, location);
+ handleNotification(jni_env, method, field, field_klass, 1, location);
if (signature_type == 'L') {
jobject newObject = new_value.l;
@@ -282,9 +282,8 @@
JNIEXPORT jboolean JNICALL
Java_FieldAccessWatch_startTest(JNIEnv *env, jclass thisClass, jobject testResults)
{
- javaEnv = env;
- testResultObject = (*javaEnv)->NewGlobalRef(javaEnv, testResults);
- testResultClass = (jclass)(*javaEnv)->NewGlobalRef(javaEnv, (*javaEnv)->GetObjectClass(javaEnv, testResultObject));
+ testResultObject = (*env)->NewGlobalRef(env, testResults);
+ testResultClass = (jclass)(*env)->NewGlobalRef(env, (*env)->GetObjectClass(env, testResultObject));
return JNI_TRUE;
}
--- a/test/jdk/ProblemList.txt Tue Apr 17 08:54:17 2018 -0700
+++ b/test/jdk/ProblemList.txt Tue Apr 17 18:18:53 2018 +0100
@@ -504,6 +504,8 @@
java/lang/management/MemoryMXBean/Pending.java 8158837 generic-all
java/lang/management/MemoryMXBean/PendingAllGC.sh 8158837 generic-all
+java/lang/management/ThreadMXBean/ThreadMXBeanStateTest.java 8081652 generic-all
+
############################################################################
# jdk_io
--- a/test/jdk/java/util/regex/RegExTest.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/jdk/java/util/regex/RegExTest.java Tue Apr 17 18:18:53 2018 +0100
@@ -35,7 +35,7 @@
* 8027645 8035076 8039124 8035975 8074678 6854417 8143854 8147531 7071819
* 8151481 4867170 7080302 6728861 6995635 6736245 4916384 6328855 6192895
* 6345469 6988218 6693451 7006761 8140212 8143282 8158482 8176029 8184706
- * 8194667 8197462
+ * 8194667 8197462 8184692
*
* @library /test/lib
* @build jdk.test.lib.RandomFactory
@@ -164,6 +164,7 @@
groupCurlyNotFoundSuppTest();
groupCurlyBackoffTest();
patternAsPredicate();
+ patternAsMatchPredicate();
invalidFlags();
embeddedFlags();
grapheme();
@@ -4689,6 +4690,26 @@
report("Pattern.asPredicate");
}
+ // This test is for 8184692
+ private static void patternAsMatchPredicate() throws Exception {
+ Predicate<String> p = Pattern.compile("[a-z]+").asMatchPredicate();
+
+ if (p.test("")) {
+ failCount++;
+ }
+ if (!p.test("word")) {
+ failCount++;
+ }
+ if (p.test("1234word")) {
+ failCount++;
+ }
+ if (p.test("1234")) {
+ failCount++;
+ }
+ report("Pattern.asMatchPredicate");
+ }
+
+
// This test is for 8035975
private static void invalidFlags() throws Exception {
for (int flag = 1; flag != 0; flag <<= 1) {
--- a/test/lib/jdk/test/lib/cds/CDSTestUtils.java Tue Apr 17 08:54:17 2018 -0700
+++ b/test/lib/jdk/test/lib/cds/CDSTestUtils.java Tue Apr 17 18:18:53 2018 +0100
@@ -117,6 +117,7 @@
private final boolean hasMappingFailure;
private final boolean hasAbnormalExit;
private final boolean hasNormalExit;
+ private final String CDS_DISABLED = "warning: CDS is disabled when the";
public Result(CDSOptions opts, OutputAnalyzer out) throws Exception {
options = opts;
@@ -126,7 +127,9 @@
hasNormalExit = (!hasMappingFailure) && (output.getExitValue() == 0);
if (hasNormalExit) {
- if ("on".equals(options.xShareMode) && output.getStderr().contains("java version")) {
+ if ("on".equals(options.xShareMode) &&
+ output.getStderr().contains("java version") &&
+ !output.getStderr().contains(CDS_DISABLED)) {
// "-showversion" is always passed in the command-line by the execXXX methods.
// During normal exit, we require that the VM to show that sharing was enabled.
output.shouldContain("sharing");
@@ -150,6 +153,26 @@
return this;
}
+ // When {--limit-modules, --patch-module, and/or --upgrade-module-path}
+ // are specified, CDS is silently disabled for both -Xshare:auto and -Xshare:on.
+ public Result assertSilentlyDisabledCDS(Checker checker) throws Exception {
+ if (hasMappingFailure) {
+ throw new RuntimeException("Unexpected mapping failure");
+ }
+ // this comes from a JVM warning message.
+ output.shouldContain(CDS_DISABLED);
+
+ checker.check(output);
+ return this;
+ }
+
+ public Result assertSilentlyDisabledCDS(int exitCode, String... matches) throws Exception {
+ return assertSilentlyDisabledCDS((out) -> {
+ out.shouldHaveExitValue(exitCode);
+ checkMatches(out, matches);
+ });
+ }
+
public Result ifNormalExit(Checker checker) throws Exception {
if (hasNormalExit) {
checker.check(output);