# HG changeset patch # User amurillo # Date 1415923860 28800 # Node ID 74c92bdda9b5fa7db16f78f8d655e045bfd0404e # Parent 82f4cb44b2d7af2352f48568a64b7b6a5ae960cd# Parent 8fe155d119af2bcad1e7fc192900cc38e551c7bc Merge diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/DefNewGeneration.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/DefNewGeneration.java Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/DefNewGeneration.java Thu Nov 13 16:11:00 2014 -0800 @@ -64,8 +64,8 @@ } // Accessing spaces - public EdenSpace eden() { - return (EdenSpace) VMObjectFactory.newObject(EdenSpace.class, edenSpaceField.getValue(addr)); + public ContiguousSpace eden() { + return (ContiguousSpace) VMObjectFactory.newObject(ContiguousSpace.class, edenSpaceField.getValue(addr)); } public ContiguousSpace from() { diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/EdenSpace.java --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/memory/EdenSpace.java Wed Jul 05 20:07:55 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. - * 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 sun.jvm.hotspot.memory; - -import java.util.*; -import sun.jvm.hotspot.debugger.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; - -/**

Class EdenSpace describes eden-space in new - generation. (Currently it does not add any significant - functionality beyond ContiguousSpace.) */ - -public class EdenSpace extends ContiguousSpace { - public EdenSpace(Address addr) { - super(addr); - } -} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/make/windows/makefiles/sa.make --- a/hotspot/make/windows/makefiles/sa.make Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/make/windows/makefiles/sa.make Thu Nov 13 16:11:00 2014 -0800 @@ -122,7 +122,7 @@ SA_LFLAGS = $(SA_LFLAGS) -map -debug !endif !if "$(BUILDARCH)" == "i486" -SA_LFLAGS = $(SAFESEH_FLAG) $(SA_LFLAGS) +SA_LFLAGS = /SAFESEH $(SA_LFLAGS) !endif SA_CFLAGS = $(SA_CFLAGS) $(MP_FLAG) diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp --- a/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/cpu/ppc/vm/templateTable_ppc_64.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -3513,7 +3513,7 @@ Rtags = R3_ARG1, Rindex = R5_ARG3; - const bool allow_shared_alloc = Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode; + const bool allow_shared_alloc = Universe::heap()->supports_inline_contig_alloc(); // -------------------------------------------------------------------------- // Check if fast case is possible. diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -2734,12 +2734,12 @@ // box->dhw disposition - post-conditions at DONE_LABEL. // - Successful inflated lock: box->dhw != 0. // Any non-zero value suffices. -// Consider G2_thread, rsp, boxReg, or unused_mark() +// Consider G2_thread, rsp, boxReg, or markOopDesc::unused_mark() // - Successful Stack-lock: box->dhw == mark. // box->dhw must contain the displaced mark word value // - Failure -- icc.ZFlag == 0 and box->dhw is undefined. // The slow-path fast_enter() and slow_enter() operators -// are responsible for setting box->dhw = NonZero (typically ::unused_mark). +// are responsible for setting box->dhw = NonZero (typically markOopDesc::unused_mark()). // - Biased: box->dhw is undefined // // SPARC refworkload performance - specifically jetstream and scimark - are @@ -2855,7 +2855,7 @@ // If m->owner != null goto IsLocked // Pessimistic form: Test-and-CAS vs CAS // The optimistic form avoids RTS->RTO cache line upgrades. - ld_ptr(Rmark, ObjectMonitor::owner_offset_in_bytes() - 2, Rscratch); + ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rscratch); andcc(Rscratch, Rscratch, G0); brx(Assembler::notZero, false, Assembler::pn, done); delayed()->nop(); @@ -2864,7 +2864,7 @@ // Try to CAS m->owner from null to Self // Invariant: if we acquire the lock then _recursions should be 0. - add(Rmark, ObjectMonitor::owner_offset_in_bytes()-2, Rmark); + add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark); mov(G2_thread, Rscratch); cas_ptr(Rmark, G0, Rscratch); cmp(Rscratch, G0); @@ -2948,7 +2948,7 @@ // Test-and-CAS vs CAS // Pessimistic form avoids futile (doomed) CAS attempts // The optimistic form avoids RTS->RTO cache line upgrades. - ld_ptr(Rmark, ObjectMonitor::owner_offset_in_bytes() - 2, Rscratch); + ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rscratch); andcc(Rscratch, Rscratch, G0); brx(Assembler::notZero, false, Assembler::pn, done); delayed()->nop(); @@ -2957,13 +2957,13 @@ // Try to CAS m->owner from null to Self // Invariant: if we acquire the lock then _recursions should be 0. - add(Rmark, ObjectMonitor::owner_offset_in_bytes()-2, Rmark); + add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark); mov(G2_thread, Rscratch); cas_ptr(Rmark, G0, Rscratch); cmp(Rscratch, G0); // ST box->displaced_header = NonZero. // Any non-zero value suffices: - // unused_mark(), G2_thread, RBox, RScratch, rsp, etc. + // markOopDesc::unused_mark(), G2_thread, RBox, RScratch, rsp, etc. st_ptr(Rbox, Rbox, BasicLock::displaced_header_offset_in_bytes()); // Intentional fall-through into done } @@ -3031,30 +3031,30 @@ // Note that we use 1-0 locking by default for the inflated case. We // close the resultant (and rare) race by having contented threads in // monitorenter periodically poll _owner. - ld_ptr(Rmark, ObjectMonitor::owner_offset_in_bytes() - 2, Rscratch); - ld_ptr(Rmark, ObjectMonitor::recursions_offset_in_bytes() - 2, Rbox); + ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rscratch); + ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions), Rbox); xor3(Rscratch, G2_thread, Rscratch); orcc(Rbox, Rscratch, Rbox); brx(Assembler::notZero, false, Assembler::pn, done); delayed()-> - ld_ptr(Rmark, ObjectMonitor::EntryList_offset_in_bytes() - 2, Rscratch); - ld_ptr(Rmark, ObjectMonitor::cxq_offset_in_bytes() - 2, Rbox); + ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList), Rscratch); + ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq), Rbox); orcc(Rbox, Rscratch, G0); if (EmitSync & 65536) { Label LSucc ; brx(Assembler::notZero, false, Assembler::pn, LSucc); delayed()->nop(); ba(done); - delayed()->st_ptr(G0, Rmark, ObjectMonitor::owner_offset_in_bytes() - 2); + delayed()->st_ptr(G0, Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)); bind(LSucc); - st_ptr(G0, Rmark, ObjectMonitor::owner_offset_in_bytes() - 2); + st_ptr(G0, Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)); if (os::is_MP()) { membar (StoreLoad); } - ld_ptr(Rmark, ObjectMonitor::succ_offset_in_bytes() - 2, Rscratch); + ld_ptr(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ), Rscratch); andcc(Rscratch, Rscratch, G0); brx(Assembler::notZero, false, Assembler::pt, done); delayed()->andcc(G0, G0, G0); - add(Rmark, ObjectMonitor::owner_offset_in_bytes()-2, Rmark); + add(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), Rmark); mov(G2_thread, Rscratch); cas_ptr(Rmark, G0, Rscratch); // invert icc.zf and goto done @@ -3066,7 +3066,7 @@ brx(Assembler::notZero, false, Assembler::pn, done); delayed()->nop(); ba(done); - delayed()->st_ptr(G0, Rmark, ObjectMonitor::owner_offset_in_bytes() - 2); + delayed()->st_ptr(G0, Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)); } bind (LStacked); @@ -3196,7 +3196,7 @@ assert(0 <= con_size_in_bytes && Assembler::is_simm13(con_size_in_bytes), "illegal object size"); assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment"); - if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) { + if (!Universe::heap()->supports_inline_contig_alloc()) { // No allocation in the shared eden. ba(slow_case); delayed()->nop(); @@ -3331,7 +3331,7 @@ assert_different_registers(top, t1, t2, t3, G4, G5 /* preserve G4 and G5 */); Label do_refill, discard_tlab; - if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) { + if (!Universe::heap()->supports_inline_contig_alloc()) { // No allocation in the shared eden. ba(slow_case); delayed()->nop(); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp --- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -3309,7 +3309,7 @@ // (creates a new TLAB, etc.) const bool allow_shared_alloc = - Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode; + Universe::heap()->supports_inline_contig_alloc(); if(UseTLAB) { Register RoldTopValue = RallocatedObject; diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -1450,8 +1450,7 @@ void MacroAssembler::rtm_retry_lock_on_busy(Register retry_count_Reg, Register box_Reg, Register tmp_Reg, Register scr_Reg, Label& retryLabel) { Label SpinLoop, SpinExit, doneRetry; - // Clean monitor_value bit to get valid pointer - int owner_offset = ObjectMonitor::owner_offset_in_bytes() - markOopDesc::monitor_value; + int owner_offset = OM_OFFSET_NO_MONITOR_VALUE_TAG(owner); testl(retry_count_Reg, retry_count_Reg); jccb(Assembler::zero, doneRetry); @@ -1532,7 +1531,7 @@ // Use RTM for inflating locks // inputs: objReg (object to lock) // boxReg (on-stack box address (displaced header location) - KILLED) -// tmpReg (ObjectMonitor address + 2(monitor_value)) +// tmpReg (ObjectMonitor address + markOopDesc::monitor_value) void MacroAssembler::rtm_inflated_locking(Register objReg, Register boxReg, Register tmpReg, Register scrReg, Register retry_on_busy_count_Reg, Register retry_on_abort_count_Reg, @@ -1543,8 +1542,7 @@ assert(tmpReg == rax, ""); assert(scrReg == rdx, ""); Label L_rtm_retry, L_decrement_retry, L_on_abort; - // Clean monitor_value bit to get valid pointer - int owner_offset = ObjectMonitor::owner_offset_in_bytes() - markOopDesc::monitor_value; + int owner_offset = OM_OFFSET_NO_MONITOR_VALUE_TAG(owner); // Without cast to int32_t a movptr will destroy r10 which is typically obj movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())); @@ -1716,7 +1714,7 @@ atomic_incl(ExternalAddress((address)counters->total_entry_count_addr()), scrReg); } if (EmitSync & 1) { - // set box->dhw = unused_mark (3) + // set box->dhw = markOopDesc::unused_mark() // Force all sync thru slow-path: slow_enter() and slow_exit() movptr (Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())); cmpptr (rsp, (int32_t)NULL_WORD); @@ -1769,7 +1767,7 @@ // at [FETCH], below, will never observe a biased encoding (*101b). // If this invariant is not held we risk exclusion (safety) failure. if (UseBiasedLocking && !UseOptoBiasInlining) { - biased_locking_enter(boxReg, objReg, tmpReg, scrReg, true, DONE_LABEL, NULL, counters); + biased_locking_enter(boxReg, objReg, tmpReg, scrReg, false, DONE_LABEL, NULL, counters); } #if INCLUDE_RTM_OPT @@ -1811,7 +1809,7 @@ jmp(DONE_LABEL); bind(IsInflated); - // The object is inflated. tmpReg contains pointer to ObjectMonitor* + 2(monitor_value) + // The object is inflated. tmpReg contains pointer to ObjectMonitor* + markOopDesc::monitor_value #if INCLUDE_RTM_OPT // Use the same RTM locking code in 32- and 64-bit VM. @@ -1823,25 +1821,10 @@ #ifndef _LP64 // The object is inflated. - // - // TODO-FIXME: eliminate the ugly use of manifest constants: - // Use markOopDesc::monitor_value instead of "2". - // use markOop::unused_mark() instead of "3". - // The tmpReg value is an objectMonitor reference ORed with - // markOopDesc::monitor_value (2). We can either convert tmpReg to an - // objectmonitor pointer by masking off the "2" bit or we can just - // use tmpReg as an objectmonitor pointer but bias the objectmonitor - // field offsets with "-2" to compensate for and annul the low-order tag bit. - // - // I use the latter as it avoids AGI stalls. - // As such, we write "mov r, [tmpReg+OFFSETOF(Owner)-2]" - // instead of "mov r, [tmpReg+OFFSETOF(Owner)]". - // - #define OFFSET_SKEWED(f) ((ObjectMonitor::f ## _offset_in_bytes())-2) // boxReg refers to the on-stack BasicLock in the current frame. // We'd like to write: - // set box->_displaced_header = markOop::unused_mark(). Any non-0 value suffices. + // set box->_displaced_header = markOopDesc::unused_mark(). Any non-0 value suffices. // This is convenient but results a ST-before-CAS penalty. The following CAS suffers // additional latency as we have another ST in the store buffer that must drain. @@ -1853,7 +1836,7 @@ if (os::is_MP()) { lock(); } - cmpxchgptr(scrReg, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)); + cmpxchgptr(scrReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); } else if ((EmitSync & 128) == 0) { // avoid ST-before-CAS movptr(scrReg, boxReg); @@ -1862,7 +1845,7 @@ // Using a prefetchw helps avoid later RTS->RTO upgrades and cache probes if ((EmitSync & 2048) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) { // prefetchw [eax + Offset(_owner)-2] - prefetchw(Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)); + prefetchw(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); } if ((EmitSync & 64) == 0) { @@ -1871,7 +1854,7 @@ } else { // Can suffer RTS->RTO upgrades on shared or cold $ lines // Test-And-CAS instead of CAS - movptr(tmpReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)); // rax, = m->_owner + movptr(tmpReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); // rax, = m->_owner testptr(tmpReg, tmpReg); // Locked ? jccb (Assembler::notZero, DONE_LABEL); } @@ -1887,11 +1870,11 @@ if (os::is_MP()) { lock(); } - cmpxchgptr(scrReg, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)); + cmpxchgptr(scrReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); movptr(Address(scrReg, 0), 3); // box->_displaced_header = 3 jccb (Assembler::notZero, DONE_LABEL); get_thread (scrReg); // beware: clobbers ICCs - movptr(Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2), scrReg); + movptr(Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), scrReg); xorptr(boxReg, boxReg); // set icc.ZFlag = 1 to indicate success // If the CAS fails we can either retry or pass control to the slow-path. @@ -1908,7 +1891,7 @@ // Using a prefetchw helps avoid later RTS->RTO upgrades and cache probes if ((EmitSync & 2048) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) { // prefetchw [eax + Offset(_owner)-2] - prefetchw(Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)); + prefetchw(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); } if ((EmitSync & 64) == 0) { @@ -1916,7 +1899,7 @@ xorptr (tmpReg, tmpReg); } else { // Can suffer RTS->RTO upgrades on shared or cold $ lines - movptr(tmpReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)); // rax, = m->_owner + movptr(tmpReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); // rax, = m->_owner testptr(tmpReg, tmpReg); // Locked ? jccb (Assembler::notZero, DONE_LABEL); } @@ -1928,7 +1911,7 @@ if (os::is_MP()) { lock(); } - cmpxchgptr(scrReg, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)); + cmpxchgptr(scrReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); // If the CAS fails we can either retry or pass control to the slow-path. // We use the latter tactic. @@ -1951,7 +1934,7 @@ movptr(Address(boxReg, 0), (int32_t)intptr_t(markOopDesc::unused_mark())); movptr (boxReg, tmpReg); - movptr (tmpReg, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)); + movptr(tmpReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); testptr(tmpReg, tmpReg); jccb (Assembler::notZero, DONE_LABEL); @@ -1959,7 +1942,7 @@ if (os::is_MP()) { lock(); } - cmpxchgptr(r15_thread, Address(boxReg, ObjectMonitor::owner_offset_in_bytes()-2)); + cmpxchgptr(r15_thread, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); // Intentional fall-through into DONE_LABEL ... #endif // _LP64 @@ -2065,8 +2048,7 @@ #if INCLUDE_RTM_OPT if (use_rtm) { Label L_regular_inflated_unlock; - // Clean monitor_value bit to get valid pointer - int owner_offset = ObjectMonitor::owner_offset_in_bytes() - markOopDesc::monitor_value; + int owner_offset = OM_OFFSET_NO_MONITOR_VALUE_TAG(owner); movptr(boxReg, Address(tmpReg, owner_offset)); testptr(boxReg, boxReg); jccb(Assembler::notZero, L_regular_inflated_unlock); @@ -2102,7 +2084,7 @@ get_thread (boxReg); if ((EmitSync & 4096) && VM_Version::supports_3dnow_prefetch() && os::is_MP()) { // prefetchw [ebx + Offset(_owner)-2] - prefetchw(Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)); + prefetchw(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); } // Note that we could employ various encoding schemes to reduce @@ -2111,21 +2093,21 @@ // In practice the chain of fetches doesn't seem to impact performance, however. if ((EmitSync & 65536) == 0 && (EmitSync & 256)) { // Attempt to reduce branch density - AMD's branch predictor. - xorptr(boxReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)); - orptr(boxReg, Address (tmpReg, ObjectMonitor::recursions_offset_in_bytes()-2)); - orptr(boxReg, Address (tmpReg, ObjectMonitor::EntryList_offset_in_bytes()-2)); - orptr(boxReg, Address (tmpReg, ObjectMonitor::cxq_offset_in_bytes()-2)); + xorptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); jccb (Assembler::notZero, DONE_LABEL); - movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), NULL_WORD); + movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); jmpb (DONE_LABEL); } else { - xorptr(boxReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)); - orptr(boxReg, Address (tmpReg, ObjectMonitor::recursions_offset_in_bytes()-2)); + xorptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); jccb (Assembler::notZero, DONE_LABEL); - movptr(boxReg, Address (tmpReg, ObjectMonitor::EntryList_offset_in_bytes()-2)); - orptr(boxReg, Address (tmpReg, ObjectMonitor::cxq_offset_in_bytes()-2)); + movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); jccb (Assembler::notZero, CheckSucc); - movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), NULL_WORD); + movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); jmpb (DONE_LABEL); } @@ -2143,7 +2125,7 @@ // Optional pre-test ... it's safe to elide this if ((EmitSync & 16) == 0) { - cmpptr(Address (tmpReg, ObjectMonitor::succ_offset_in_bytes()-2), (int32_t)NULL_WORD); + cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD); jccb (Assembler::zero, LGoSlowPath); } @@ -2173,7 +2155,7 @@ // We currently use (3), although it's likely that switching to (2) // is correct for the future. - movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), NULL_WORD); + movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); if (os::is_MP()) { if (VM_Version::supports_sse2() && 1 == FenceInstruction) { mfence(); @@ -2182,18 +2164,18 @@ } } // Ratify _succ remains non-null - cmpptr(Address (tmpReg, ObjectMonitor::succ_offset_in_bytes()-2), 0); + cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), 0); jccb (Assembler::notZero, LSuccess); xorptr(boxReg, boxReg); // box is really EAX if (os::is_MP()) { lock(); } - cmpxchgptr(rsp, Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)); + cmpxchgptr(rsp, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); jccb (Assembler::notEqual, LSuccess); // Since we're low on registers we installed rsp as a placeholding in _owner. // Now install Self over rsp. This is safe as we're transitioning from // non-null to non=null get_thread (boxReg); - movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), boxReg); + movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), boxReg); // Intentional fall-through into LGoSlowPath ... bind (LGoSlowPath); @@ -2228,36 +2210,36 @@ } #else // _LP64 // It's inflated - movptr(boxReg, Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)); + movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); xorptr(boxReg, r15_thread); - orptr (boxReg, Address (tmpReg, ObjectMonitor::recursions_offset_in_bytes()-2)); + orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); jccb (Assembler::notZero, DONE_LABEL); - movptr(boxReg, Address (tmpReg, ObjectMonitor::cxq_offset_in_bytes()-2)); - orptr (boxReg, Address (tmpReg, ObjectMonitor::EntryList_offset_in_bytes()-2)); + movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); + orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); jccb (Assembler::notZero, CheckSucc); - movptr(Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), (int32_t)NULL_WORD); + movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD); jmpb (DONE_LABEL); if ((EmitSync & 65536) == 0) { Label LSuccess, LGoSlowPath ; bind (CheckSucc); - cmpptr(Address (tmpReg, ObjectMonitor::succ_offset_in_bytes()-2), (int32_t)NULL_WORD); + cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD); jccb (Assembler::zero, LGoSlowPath); // I'd much rather use lock:andl m->_owner, 0 as it's faster than the // the explicit ST;MEMBAR combination, but masm doesn't currently support // "ANDQ M,IMM". Don't use MFENCE here. lock:add to TOS, xchg, etc // are all faster when the write buffer is populated. - movptr (Address (tmpReg, ObjectMonitor::owner_offset_in_bytes()-2), (int32_t)NULL_WORD); + movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD); if (os::is_MP()) { lock (); addl (Address(rsp, 0), 0); } - cmpptr(Address (tmpReg, ObjectMonitor::succ_offset_in_bytes()-2), (int32_t)NULL_WORD); + cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD); jccb (Assembler::notZero, LSuccess); movptr (boxReg, (int32_t)NULL_WORD); // box is really EAX if (os::is_MP()) { lock(); } - cmpxchgptr(r15_thread, Address(tmpReg, ObjectMonitor::owner_offset_in_bytes()-2)); + cmpxchgptr(r15_thread, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); jccb (Assembler::notEqual, LSuccess); // Intentional fall-through into slow-path @@ -2964,7 +2946,7 @@ Label& slow_case) { assert(obj == rax, "obj must be in rax, for cmpxchg"); assert_different_registers(obj, var_size_in_bytes, t1); - if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) { + if (!Universe::heap()->supports_inline_contig_alloc()) { jmp(slow_case); } else { Register end = t1; @@ -4437,7 +4419,7 @@ assert_different_registers(top, thread_reg, t1, t2, /* preserve: */ rbx, rdx); Label do_refill, discard_tlab; - if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) { + if (!Universe::heap()->supports_inline_contig_alloc()) { // No allocation in the shared eden. jmp(slow_case); } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp --- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -3214,7 +3214,7 @@ // (creates a new TLAB, etc.) const bool allow_shared_alloc = - Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode; + Universe::heap()->supports_inline_contig_alloc(); const Register thread = rcx; if (UseTLAB || allow_shared_alloc) { diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp --- a/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/cpu/x86/vm/templateTable_x86_64.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -3269,7 +3269,7 @@ // (creates a new TLAB, etc.) const bool allow_shared_alloc = - Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode; + Universe::heap()->supports_inline_contig_alloc(); if (UseTLAB) { __ movptr(rax, Address(r15_thread, in_bytes(JavaThread::tlab_top_offset()))); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/os/solaris/vm/os_solaris.cpp --- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -2608,7 +2608,10 @@ assert((intptr_t)addr % alignment_hint == 0, "Address should be aligned."); assert((intptr_t)(addr + bytes) % alignment_hint == 0, "End should be aligned."); if (UseLargePages) { - Solaris::setup_large_pages(addr, bytes, alignment_hint); + size_t page_size = Solaris::page_size_for_alignment(alignment_hint); + if (page_size > (size_t) vm_page_size()) { + Solaris::setup_large_pages(addr, bytes, page_size); + } } } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp --- a/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -31,6 +31,11 @@ // Implementation of class OrderAccess. +// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions +static inline void compiler_barrier() { + __asm__ volatile ("" : : : "memory"); +} + inline void OrderAccess::loadload() { acquire(); } inline void OrderAccess::storestore() { release(); } inline void OrderAccess::loadstore() { acquire(); } @@ -46,9 +51,7 @@ } inline void OrderAccess::release() { - // Avoid hitting the same cache-line from - // different threads. - volatile jint local_dummy = 0; + compiler_barrier(); } inline void OrderAccess::fence() { @@ -62,34 +65,34 @@ } } -inline jbyte OrderAccess::load_acquire(volatile jbyte* p) { return *p; } -inline jshort OrderAccess::load_acquire(volatile jshort* p) { return *p; } -inline jint OrderAccess::load_acquire(volatile jint* p) { return *p; } -inline jlong OrderAccess::load_acquire(volatile jlong* p) { return Atomic::load(p); } -inline jubyte OrderAccess::load_acquire(volatile jubyte* p) { return *p; } -inline jushort OrderAccess::load_acquire(volatile jushort* p) { return *p; } -inline juint OrderAccess::load_acquire(volatile juint* p) { return *p; } -inline julong OrderAccess::load_acquire(volatile julong* p) { return Atomic::load((volatile jlong*)p); } -inline jfloat OrderAccess::load_acquire(volatile jfloat* p) { return *p; } -inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { return jdouble_cast(Atomic::load((volatile jlong*)p)); } +inline jbyte OrderAccess::load_acquire(volatile jbyte* p) { jbyte v = *p; compiler_barrier(); return v; } +inline jshort OrderAccess::load_acquire(volatile jshort* p) { jshort v = *p; compiler_barrier(); return v; } +inline jint OrderAccess::load_acquire(volatile jint* p) { jint v = *p; compiler_barrier(); return v; } +inline jlong OrderAccess::load_acquire(volatile jlong* p) { jlong v = Atomic::load(p); compiler_barrier(); return v; } +inline jubyte OrderAccess::load_acquire(volatile jubyte* p) { jubyte v = *p; compiler_barrier(); return v; } +inline jushort OrderAccess::load_acquire(volatile jushort* p) { jushort v = *p; compiler_barrier(); return v; } +inline juint OrderAccess::load_acquire(volatile juint* p) { juint v = *p; compiler_barrier(); return v; } +inline julong OrderAccess::load_acquire(volatile julong* p) { julong v = Atomic::load((volatile jlong*)p); compiler_barrier(); return v; } +inline jfloat OrderAccess::load_acquire(volatile jfloat* p) { jfloat v = *p; compiler_barrier(); return v; } +inline jdouble OrderAccess::load_acquire(volatile jdouble* p) { jdouble v = jdouble_cast(Atomic::load((volatile jlong*)p)); compiler_barrier(); return v; } -inline intptr_t OrderAccess::load_ptr_acquire(volatile intptr_t* p) { return *p; } -inline void* OrderAccess::load_ptr_acquire(volatile void* p) { return *(void* volatile *)p; } -inline void* OrderAccess::load_ptr_acquire(const volatile void* p) { return *(void* const volatile *)p; } +inline intptr_t OrderAccess::load_ptr_acquire(volatile intptr_t* p) { intptr_t v = *p; compiler_barrier(); return v; } +inline void* OrderAccess::load_ptr_acquire(volatile void* p) { void* v = *(void* volatile *)p; compiler_barrier(); return v; } +inline void* OrderAccess::load_ptr_acquire(const volatile void* p) { void* v = *(void* const volatile *)p; compiler_barrier(); return v; } -inline void OrderAccess::release_store(volatile jbyte* p, jbyte v) { *p = v; } -inline void OrderAccess::release_store(volatile jshort* p, jshort v) { *p = v; } -inline void OrderAccess::release_store(volatile jint* p, jint v) { *p = v; } -inline void OrderAccess::release_store(volatile jlong* p, jlong v) { Atomic::store(v, p); } -inline void OrderAccess::release_store(volatile jubyte* p, jubyte v) { *p = v; } -inline void OrderAccess::release_store(volatile jushort* p, jushort v) { *p = v; } -inline void OrderAccess::release_store(volatile juint* p, juint v) { *p = v; } -inline void OrderAccess::release_store(volatile julong* p, julong v) { Atomic::store((jlong)v, (volatile jlong*)p); } -inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { *p = v; } +inline void OrderAccess::release_store(volatile jbyte* p, jbyte v) { compiler_barrier(); *p = v; } +inline void OrderAccess::release_store(volatile jshort* p, jshort v) { compiler_barrier(); *p = v; } +inline void OrderAccess::release_store(volatile jint* p, jint v) { compiler_barrier(); *p = v; } +inline void OrderAccess::release_store(volatile jlong* p, jlong v) { compiler_barrier(); Atomic::store(v, p); } +inline void OrderAccess::release_store(volatile jubyte* p, jubyte v) { compiler_barrier(); *p = v; } +inline void OrderAccess::release_store(volatile jushort* p, jushort v) { compiler_barrier(); *p = v; } +inline void OrderAccess::release_store(volatile juint* p, juint v) { compiler_barrier(); *p = v; } +inline void OrderAccess::release_store(volatile julong* p, julong v) { compiler_barrier(); Atomic::store((jlong)v, (volatile jlong*)p); } +inline void OrderAccess::release_store(volatile jfloat* p, jfloat v) { compiler_barrier(); *p = v; } inline void OrderAccess::release_store(volatile jdouble* p, jdouble v) { release_store((volatile jlong *)p, jlong_cast(v)); } -inline void OrderAccess::release_store_ptr(volatile intptr_t* p, intptr_t v) { *p = v; } -inline void OrderAccess::release_store_ptr(volatile void* p, void* v) { *(void* volatile *)p = v; } +inline void OrderAccess::release_store_ptr(volatile intptr_t* p, intptr_t v) { compiler_barrier(); *p = v; } +inline void OrderAccess::release_store_ptr(volatile void* p, void* v) { compiler_barrier(); *(void* volatile *)p = v; } inline void OrderAccess::store_fence(jbyte* p, jbyte v) { __asm__ volatile ( "xchgb (%2),%0" diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/Xusage.txt --- a/hotspot/src/share/vm/Xusage.txt Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/Xusage.txt Thu Nov 13 16:11:00 2014 -0800 @@ -7,7 +7,6 @@ -Xbootclasspath/p: prepend in front of bootstrap class path -Xnoclassgc disable class garbage collection - -Xincgc enable incremental garbage collection -Xloggc: log GC status to a file with time stamps -Xbatch disable background compilation -Xms set initial Java heap size diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/ci/ciMethod.cpp --- a/hotspot/src/share/vm/ci/ciMethod.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -68,7 +68,10 @@ // ciMethod::ciMethod // // Loaded method. -ciMethod::ciMethod(methodHandle h_m) : ciMetadata(h_m()) { +ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) : + ciMetadata(h_m()), + _holder(holder) +{ assert(h_m() != NULL, "no null method"); // These fields are always filled in in loaded methods. @@ -124,7 +127,6 @@ // generating _signature may allow GC and therefore move m. // These fields are always filled in. _name = env->get_symbol(h_m()->name()); - _holder = env->get_instance_klass(h_m()->method_holder()); ciSymbol* sig_symbol = env->get_symbol(h_m()->signature()); constantPoolHandle cpool = h_m()->constants(); _signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/ci/ciMethod.hpp --- a/hotspot/src/share/vm/ci/ciMethod.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciMethod.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -91,7 +91,7 @@ BCEscapeAnalyzer* _bcea; #endif - ciMethod(methodHandle h_m); + ciMethod(methodHandle h_m, ciInstanceKlass* holder); ciMethod(ciInstanceKlass* holder, ciSymbol* name, ciSymbol* signature, ciInstanceKlass* accessor); Method* get_Method() const { diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/ci/ciObjectFactory.cpp --- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -239,7 +239,7 @@ ciObject* ciObjectFactory::get(oop key) { ASSERT_IN_VM; - assert(key == NULL || Universe::heap()->is_in_reserved(key), "must be"); + assert(Universe::heap()->is_in_reserved(key), "must be"); NonPermObject* &bucket = find_non_perm(key); if (bucket != NULL) { @@ -260,10 +260,10 @@ } // ------------------------------------------------------------------ -// ciObjectFactory::get +// ciObjectFactory::get_metadata // -// Get the ciObject corresponding to some oop. If the ciObject has -// already been created, it is returned. Otherwise, a new ciObject +// Get the ciMetadata corresponding to some Metadata. If the ciMetadata has +// already been created, it is returned. Otherwise, a new ciMetadata // is created. ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { ASSERT_IN_VM; @@ -290,9 +290,9 @@ } #endif if (!is_found_at(index, key, _ci_metadata)) { - // The ciObject does not yet exist. Create it and insert it + // The ciMetadata does not yet exist. Create it and insert it // into the cache. - ciMetadata* new_object = create_new_object(key); + ciMetadata* new_object = create_new_metadata(key); init_ident_of(new_object); assert(new_object->is_metadata(), "must be"); @@ -344,15 +344,28 @@ } // ------------------------------------------------------------------ -// ciObjectFactory::create_new_object +// ciObjectFactory::create_new_metadata // -// Create a new ciObject from a Metadata*. +// Create a new ciMetadata from a Metadata*. // -// Implementation note: this functionality could be virtual behavior -// of the oop itself. For now, we explicitly marshal the object. -ciMetadata* ciObjectFactory::create_new_object(Metadata* o) { +// Implementation note: in order to keep Metadata live, an auxiliary ciObject +// is used, which points to it's holder. +ciMetadata* ciObjectFactory::create_new_metadata(Metadata* o) { EXCEPTION_CONTEXT; + // Hold metadata from unloading by keeping it's holder alive. + if (_initialized && o->is_klass()) { + Klass* holder = ((Klass*)o); + if (holder->oop_is_instance() && InstanceKlass::cast(holder)->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. + // It is enough to record a ciObject, since cached elements are never removed + // during ciObjectFactory lifetime. ciObjectFactory itself is created for + // every compilation and lives for the whole duration of the compilation. + ciObject* h = get(holder->klass_holder()); + } + } + if (o->is_klass()) { KlassHandle h_k(THREAD, (Klass*)o); Klass* k = (Klass*)o; @@ -365,14 +378,16 @@ } } else if (o->is_method()) { methodHandle h_m(THREAD, (Method*)o); - return new (arena()) ciMethod(h_m); + ciEnv *env = CURRENT_THREAD_ENV; + ciInstanceKlass* holder = env->get_instance_klass(h_m()->method_holder()); + return new (arena()) ciMethod(h_m, holder); } else if (o->is_methodData()) { // Hold methodHandle alive - might not be necessary ??? methodHandle h_m(THREAD, ((MethodData*)o)->method()); return new (arena()) ciMethodData((MethodData*)o); } - // The oop is of some type not supported by the compiler interface. + // The Metadata* is of some type not supported by the compiler interface. ShouldNotReachHere(); return NULL; } @@ -701,7 +716,7 @@ // If there is no entry in the cache corresponding to this oop, return // the null tail of the bucket into which the oop should be inserted. ciObjectFactory::NonPermObject* &ciObjectFactory::find_non_perm(oop key) { - assert(Universe::heap()->is_in_reserved_or_null(key), "must be"); + assert(Universe::heap()->is_in_reserved(key), "must be"); ciMetadata* klass = get_metadata(key->klass()); NonPermObject* *bp = &_non_perm_bucket[(unsigned) klass->hash() % NON_PERM_BUCKETS]; for (NonPermObject* p; (p = (*bp)) != NULL; bp = &p->next()) { diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/ci/ciObjectFactory.hpp --- a/hotspot/src/share/vm/ci/ciObjectFactory.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/ci/ciObjectFactory.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -73,7 +73,7 @@ void insert(int index, ciMetadata* obj, GrowableArray* objects); ciObject* create_new_object(oop o); - ciMetadata* create_new_object(Metadata* o); + ciMetadata* create_new_metadata(Metadata* o); void ensure_metadata_alive(ciMetadata* m); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -2059,7 +2059,7 @@ u2** localvariable_table_start; u2* localvariable_type_table_length; u2** localvariable_type_table_start; - u2 method_parameters_length = 0; + int method_parameters_length = -1; u1* method_parameters_data = NULL; bool method_parameters_seen = false; bool parsed_code_attribute = false; @@ -2278,7 +2278,8 @@ } method_parameters_seen = true; method_parameters_length = cfs->get_u1_fast(); - if (method_attribute_length != (method_parameters_length * 4u) + 1u) { + const u2 real_length = (method_parameters_length * 4u) + 1u; + if (method_attribute_length != real_length) { classfile_parse_error( "Invalid MethodParameters method attribute length %u in class file", method_attribute_length, CHECK_(nullHandle)); @@ -2288,7 +2289,7 @@ cfs->skip_u2_fast(method_parameters_length); // ignore this attribute if it cannot be reflected if (!SystemDictionary::Parameter_klass_loaded()) - method_parameters_length = 0; + method_parameters_length = -1; } else if (method_attribute_name == vmSymbols::tag_synthetic()) { if (method_attribute_length != 0) { classfile_parse_error( @@ -3491,17 +3492,18 @@ real_offset = next_nonstatic_oop_offset; next_nonstatic_oop_offset += heapOopSize; } - // Update oop maps + + // Record this oop in the oop maps if( nonstatic_oop_map_count > 0 && nonstatic_oop_offsets[nonstatic_oop_map_count - 1] == real_offset - int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) * heapOopSize ) { - // Extend current oop map + // This oop is adjacent to the previous one, add to current oop map assert(nonstatic_oop_map_count - 1 < max_nonstatic_oop_maps, "range check"); nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1; } else { - // Create new oop map + // This oop is not adjacent to the previous one, create new oop map assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check"); nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; nonstatic_oop_counts [nonstatic_oop_map_count] = 1; @@ -3623,13 +3625,24 @@ real_offset = next_nonstatic_padded_offset; next_nonstatic_padded_offset += heapOopSize; - // Create new oop map - assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check"); - nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; - nonstatic_oop_counts [nonstatic_oop_map_count] = 1; - nonstatic_oop_map_count += 1; - if( first_nonstatic_oop_offset == 0 ) { // Undefined - first_nonstatic_oop_offset = real_offset; + // Record this oop in the oop maps + if( nonstatic_oop_map_count > 0 && + nonstatic_oop_offsets[nonstatic_oop_map_count - 1] == + real_offset - + int(nonstatic_oop_counts[nonstatic_oop_map_count - 1]) * + heapOopSize ) { + // This oop is adjacent to the previous one, add to current oop map + assert(nonstatic_oop_map_count - 1 < max_nonstatic_oop_maps, "range check"); + nonstatic_oop_counts[nonstatic_oop_map_count - 1] += 1; + } else { + // This oop is not adjacent to the previous one, create new oop map + assert(nonstatic_oop_map_count < max_nonstatic_oop_maps, "range check"); + nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset; + nonstatic_oop_counts [nonstatic_oop_map_count] = 1; + nonstatic_oop_map_count += 1; + if( first_nonstatic_oop_offset == 0 ) { // Undefined + first_nonstatic_oop_offset = real_offset; + } } break; diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/classfile/classLoader.cpp --- a/hotspot/src/share/vm/classfile/classLoader.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/classfile/classLoader.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -1120,7 +1120,7 @@ h = context.record_result(classpath_index, e, result, THREAD); } else { if (DumpSharedSpaces) { - tty->print_cr("Preload Error: Cannot find %s", class_name); + tty->print_cr("Preload Warning: Cannot find %s", class_name); } } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/classfile/dictionary.cpp --- a/hotspot/src/share/vm/classfile/dictionary.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/classfile/dictionary.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -223,7 +223,7 @@ } free_entry(probe); ResourceMark rm; - tty->print_cr("Removed error class: %s", ik->external_name()); + tty->print_cr("Preload Warning: Removed error class: %s", ik->external_name()); continue; } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/code/codeBlob.cpp --- a/hotspot/src/share/vm/code/codeBlob.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/code/codeBlob.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -43,7 +43,7 @@ #include "c1/c1_Runtime1.hpp" #endif -unsigned int align_code_offset(int offset) { +unsigned int CodeBlob::align_code_offset(int offset) { // align the size to CodeEntryAlignment return ((offset + (int)CodeHeap::header_size() + (CodeEntryAlignment-1)) & ~(CodeEntryAlignment-1)) diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/code/codeBlob.hpp --- a/hotspot/src/share/vm/code/codeBlob.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/code/codeBlob.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -83,6 +83,7 @@ public: // Returns the space needed for CodeBlob static unsigned int allocation_size(CodeBuffer* cb, int header_size); + static unsigned int align_code_offset(int offset); // Creation // a) simple CodeBlob @@ -207,7 +208,7 @@ } }; - +class WhiteBox; //---------------------------------------------------------------------------------------------------- // BufferBlob: used to hold non-relocatable machine code such as the interpreter, stubroutines, etc. @@ -215,6 +216,7 @@ friend class VMStructs; friend class AdapterBlob; friend class MethodHandlesAdapterBlob; + friend class WhiteBox; private: // Creation support diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/code/codeCache.cpp --- a/hotspot/src/share/vm/code/codeCache.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/code/codeCache.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -305,7 +305,7 @@ MemoryService::add_code_heap_memory_pool(heap, name); } -CodeHeap* CodeCache::get_code_heap(CodeBlob* cb) { +CodeHeap* CodeCache::get_code_heap(const CodeBlob* cb) { assert(cb != NULL, "CodeBlob is null"); FOR_ALL_HEAPS(heap) { if ((*heap)->contains(cb)) { diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/code/codeCache.hpp --- a/hotspot/src/share/vm/code/codeCache.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/code/codeCache.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -77,6 +77,7 @@ class CodeCache : AllStatic { friend class VMStructs; friend class NMethodIterator; + friend class WhiteBox; private: // CodeHeaps of the cache static GrowableArray* _heaps; @@ -98,7 +99,7 @@ static void initialize_heaps(); // Initializes the CodeHeaps // Creates a new heap with the given name and size, containing CodeBlobs of the given type static void add_heap(ReservedSpace rs, const char* name, size_t size_initial, int code_blob_type); - static CodeHeap* get_code_heap(CodeBlob* cb); // Returns the CodeHeap for the given CodeBlob + static CodeHeap* get_code_heap(const CodeBlob* cb); // Returns the CodeHeap for the given CodeBlob static CodeHeap* get_code_heap(int code_blob_type); // Returns the CodeHeap for the given CodeBlobType // Returns the name of the VM option to set the size of the corresponding CodeHeap static const char* get_code_heap_flag_name(int code_blob_type); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/compiler/compileBroker.cpp --- a/hotspot/src/share/vm/compiler/compileBroker.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -35,6 +35,7 @@ #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "prims/nativeLookup.hpp" +#include "prims/whitebox.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/compilationPolicy.hpp" @@ -1963,6 +1964,12 @@ if (comp == NULL) { ci_env.record_method_not_compilable("no compiler", !TieredCompilation); } else { + if (WhiteBoxAPI && WhiteBox::compilation_locked) { + MonitorLockerEx locker(Compilation_lock, Mutex::_no_safepoint_check_flag); + while (WhiteBox::compilation_locked) { + locker.wait(Mutex::_no_safepoint_check_flag); + } + } comp->compile_method(&ci_env, target, osr_bci); } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -89,9 +89,3 @@ _gc_policy_counters = new GCPolicyCounters("Copy:CMS", 2, 3); } } - -// Returns true if the incremental mode is enabled. -bool ConcurrentMarkSweepPolicy::has_soft_ended_eden() -{ - return CMSIncrementalMode; -} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -42,9 +42,6 @@ virtual void initialize_size_policy(size_t init_eden_size, size_t init_promo_size, size_t init_survivor_size); - - // Returns true if the incremental mode is enabled. - virtual bool has_soft_ended_eden(); }; #endif // SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CMSCOLLECTORPOLICY_HPP diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -2083,17 +2083,13 @@ } // Support for compaction - void CompactibleFreeListSpace::prepare_for_compaction(CompactPoint* cp) { - SCAN_AND_FORWARD(cp,end,block_is_obj,block_size); + scan_and_forward(this, cp); // Prepare_for_compaction() uses the space between live objects // so that later phase can skip dead space quickly. So verification // of the free lists doesn't work after. } -#define obj_size(q) adjustObjectSize(oop(q)->size()) -#define adjust_obj_size(s) adjustObjectSize(s) - void CompactibleFreeListSpace::adjust_pointers() { // In other versions of adjust_pointers(), a bail out // based on the amount of live data in the generation @@ -2101,12 +2097,12 @@ // Cannot test used() == 0 here because the free lists have already // been mangled by the compaction. - SCAN_AND_ADJUST_POINTERS(adjust_obj_size); + scan_and_adjust_pointers(this); // See note about verification in prepare_for_compaction(). } void CompactibleFreeListSpace::compact() { - SCAN_AND_COMPACT(obj_size); + scan_and_compact(this); } // Fragmentation metric = 1 - [sum of (fbs**2) / (sum of fbs)**2] @@ -2629,7 +2625,7 @@ // Get the #blocks we want to claim size_t n_blks = (size_t)_blocks_to_claim[word_sz].average(); assert(n_blks > 0, "Error"); - assert(ResizePLAB || n_blks == OldPLABSize, "Error"); + assert(ResizeOldPLAB || n_blks == OldPLABSize, "Error"); // In some cases, when the application has a phase change, // there may be a sudden and sharp shift in the object survival // profile, and updating the counts at the end of a scavenge diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -73,6 +73,13 @@ friend class CMSCollector; // Local alloc buffer for promotion into this space. friend class CFLS_LAB; + // Allow scan_and_* functions to call (private) overrides of the auxiliary functions on this class + template + friend void CompactibleSpace::scan_and_adjust_pointers(SpaceType* space); + template + friend void CompactibleSpace::scan_and_compact(SpaceType* space); + template + friend void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp); // "Size" of chunks of work (executed during parallel remark phases // of CMS collection); this probably belongs in CMSCollector, although @@ -288,6 +295,28 @@ _bt.freed(start, size); } + // Auxiliary functions for scan_and_{forward,adjust_pointers,compact} support. + // See comments for CompactibleSpace for more information. + inline HeapWord* scan_limit() const { + return end(); + } + + inline bool scanned_block_is_obj(const HeapWord* addr) const { + return CompactibleFreeListSpace::block_is_obj(addr); // Avoid virtual call + } + + inline size_t scanned_block_size(const HeapWord* addr) const { + return CompactibleFreeListSpace::block_size(addr); // Avoid virtual call + } + + inline size_t adjust_obj_size(size_t size) const { + return adjustObjectSize(size); + } + + inline size_t obj_size(const HeapWord* addr) const { + return adjustObjectSize(oop(addr)->size()); + } + protected: // Reset the indexed free list to its initial empty condition. void resetIndexedFreeListArray(); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -167,16 +167,6 @@ }; -// Wrapper class to temporarily disable icms during a foreground cms collection. -class ICMSDisabler: public StackObj { - public: - // The ctor disables icms and wakes up the thread so it notices the change; - // the dtor re-enables icms. Note that the CMSCollector methods will check - // CMSIncrementalMode. - ICMSDisabler() { CMSCollector::disable_icms(); CMSCollector::start_icms(); } - ~ICMSDisabler() { CMSCollector::enable_icms(); } -}; - ////////////////////////////////////////////////////////////////// // Concurrent Mark-Sweep Generation ///////////////////////////// ////////////////////////////////////////////////////////////////// @@ -363,7 +353,6 @@ _cms_used_at_gc0_end = 0; _allow_duty_cycle_reduction = false; _valid_bits = 0; - _icms_duty_cycle = CMSIncrementalDutyCycle; } double CMSStats::cms_free_adjustment_factor(size_t free) const { @@ -442,86 +431,17 @@ return work - deadline; } -// Return a duty cycle based on old_duty_cycle and new_duty_cycle, limiting the -// amount of change to prevent wild oscillation. -unsigned int CMSStats::icms_damped_duty_cycle(unsigned int old_duty_cycle, - unsigned int new_duty_cycle) { - assert(old_duty_cycle <= 100, "bad input value"); - assert(new_duty_cycle <= 100, "bad input value"); - - // Note: use subtraction with caution since it may underflow (values are - // unsigned). Addition is safe since we're in the range 0-100. - unsigned int damped_duty_cycle = new_duty_cycle; - if (new_duty_cycle < old_duty_cycle) { - const unsigned int largest_delta = MAX2(old_duty_cycle / 4, 5U); - if (new_duty_cycle + largest_delta < old_duty_cycle) { - damped_duty_cycle = old_duty_cycle - largest_delta; - } - } else if (new_duty_cycle > old_duty_cycle) { - const unsigned int largest_delta = MAX2(old_duty_cycle / 4, 15U); - if (new_duty_cycle > old_duty_cycle + largest_delta) { - damped_duty_cycle = MIN2(old_duty_cycle + largest_delta, 100U); - } - } - assert(damped_duty_cycle <= 100, "invalid duty cycle computed"); - - if (CMSTraceIncrementalPacing) { - gclog_or_tty->print(" [icms_damped_duty_cycle(%d,%d) = %d] ", - old_duty_cycle, new_duty_cycle, damped_duty_cycle); - } - return damped_duty_cycle; -} - -unsigned int CMSStats::icms_update_duty_cycle_impl() { - assert(CMSIncrementalPacing && valid(), - "should be handled in icms_update_duty_cycle()"); - - double cms_time_so_far = cms_timer().seconds(); - double scaled_duration = cms_duration_per_mb() * _cms_used_at_gc0_end / M; - double scaled_duration_remaining = fabsd(scaled_duration - cms_time_so_far); - - // Avoid division by 0. - double time_until_full = MAX2(time_until_cms_gen_full(), 0.01); - double duty_cycle_dbl = 100.0 * scaled_duration_remaining / time_until_full; - - unsigned int new_duty_cycle = MIN2((unsigned int)duty_cycle_dbl, 100U); - if (new_duty_cycle > _icms_duty_cycle) { - // Avoid very small duty cycles (1 or 2); 0 is allowed. - if (new_duty_cycle > 2) { - _icms_duty_cycle = icms_damped_duty_cycle(_icms_duty_cycle, - new_duty_cycle); - } - } else if (_allow_duty_cycle_reduction) { - // The duty cycle is reduced only once per cms cycle (see record_cms_end()). - new_duty_cycle = icms_damped_duty_cycle(_icms_duty_cycle, new_duty_cycle); - // Respect the minimum duty cycle. - unsigned int min_duty_cycle = (unsigned int)CMSIncrementalDutyCycleMin; - _icms_duty_cycle = MAX2(new_duty_cycle, min_duty_cycle); - } - - if (PrintGCDetails || CMSTraceIncrementalPacing) { - gclog_or_tty->print(" icms_dc=%d ", _icms_duty_cycle); - } - - _allow_duty_cycle_reduction = false; - return _icms_duty_cycle; -} - #ifndef PRODUCT void CMSStats::print_on(outputStream *st) const { st->print(" gc0_alpha=%d,cms_alpha=%d", _gc0_alpha, _cms_alpha); st->print(",gc0_dur=%g,gc0_per=%g,gc0_promo=" SIZE_FORMAT, gc0_duration(), gc0_period(), gc0_promoted()); - st->print(",cms_dur=%g,cms_dur_per_mb=%g,cms_per=%g,cms_alloc=" SIZE_FORMAT, - cms_duration(), cms_duration_per_mb(), - cms_period(), cms_allocated()); + st->print(",cms_dur=%g,cms_per=%g,cms_alloc=" SIZE_FORMAT, + cms_duration(), cms_period(), cms_allocated()); st->print(",cms_since_beg=%g,cms_since_end=%g", cms_time_since_begin(), cms_time_since_end()); st->print(",cms_used_beg=" SIZE_FORMAT ",cms_used_end=" SIZE_FORMAT, _cms_used_at_gc0_begin, _cms_used_at_gc0_end); - if (CMSIncrementalMode) { - st->print(",dc=%d", icms_duty_cycle()); - } if (valid()) { st->print(",promo_rate=%g,cms_alloc_rate=%g", @@ -579,8 +499,6 @@ #endif _collection_count_start(0), _verifying(false), - _icms_start_limit(NULL), - _icms_stop_limit(NULL), _verification_mark_bm(0, Mutex::leaf + 1, "CMS_verification_mark_bm_lock"), _completed_initialization(false), _collector_policy(cp), @@ -1116,137 +1034,6 @@ } } -static inline size_t percent_of_space(Space* space, HeapWord* addr) -{ - size_t delta = pointer_delta(addr, space->bottom()); - return (size_t)(delta * 100.0 / (space->capacity() / HeapWordSize)); -} - -void CMSCollector::icms_update_allocation_limits() -{ - Generation* young = GenCollectedHeap::heap()->get_gen(0); - EdenSpace* eden = young->as_DefNewGeneration()->eden(); - - const unsigned int duty_cycle = stats().icms_update_duty_cycle(); - if (CMSTraceIncrementalPacing) { - stats().print(); - } - - assert(duty_cycle <= 100, "invalid duty cycle"); - if (duty_cycle != 0) { - // The duty_cycle is a percentage between 0 and 100; convert to words and - // then compute the offset from the endpoints of the space. - size_t free_words = eden->free() / HeapWordSize; - double free_words_dbl = (double)free_words; - size_t duty_cycle_words = (size_t)(free_words_dbl * duty_cycle / 100.0); - size_t offset_words = (free_words - duty_cycle_words) / 2; - - _icms_start_limit = eden->top() + offset_words; - _icms_stop_limit = eden->end() - offset_words; - - // The limits may be adjusted (shifted to the right) by - // CMSIncrementalOffset, to allow the application more mutator time after a - // young gen gc (when all mutators were stopped) and before CMS starts and - // takes away one or more cpus. - if (CMSIncrementalOffset != 0) { - double adjustment_dbl = free_words_dbl * CMSIncrementalOffset / 100.0; - size_t adjustment = (size_t)adjustment_dbl; - HeapWord* tmp_stop = _icms_stop_limit + adjustment; - if (tmp_stop > _icms_stop_limit && tmp_stop < eden->end()) { - _icms_start_limit += adjustment; - _icms_stop_limit = tmp_stop; - } - } - } - if (duty_cycle == 0 || (_icms_start_limit == _icms_stop_limit)) { - _icms_start_limit = _icms_stop_limit = eden->end(); - } - - // Install the new start limit. - eden->set_soft_end(_icms_start_limit); - - if (CMSTraceIncrementalMode) { - gclog_or_tty->print(" icms alloc limits: " - PTR_FORMAT "," PTR_FORMAT - " (" SIZE_FORMAT "%%," SIZE_FORMAT "%%) ", - p2i(_icms_start_limit), p2i(_icms_stop_limit), - percent_of_space(eden, _icms_start_limit), - percent_of_space(eden, _icms_stop_limit)); - if (Verbose) { - gclog_or_tty->print("eden: "); - eden->print_on(gclog_or_tty); - } - } -} - -// Any changes here should try to maintain the invariant -// that if this method is called with _icms_start_limit -// and _icms_stop_limit both NULL, then it should return NULL -// and not notify the icms thread. -HeapWord* -CMSCollector::allocation_limit_reached(Space* space, HeapWord* top, - size_t word_size) -{ - // A start_limit equal to end() means the duty cycle is 0, so treat that as a - // nop. - if (CMSIncrementalMode && _icms_start_limit != space->end()) { - if (top <= _icms_start_limit) { - if (CMSTraceIncrementalMode) { - space->print_on(gclog_or_tty); - gclog_or_tty->stamp(); - gclog_or_tty->print_cr(" start limit top=" PTR_FORMAT - ", new limit=" PTR_FORMAT - " (" SIZE_FORMAT "%%)", - p2i(top), p2i(_icms_stop_limit), - percent_of_space(space, _icms_stop_limit)); - } - ConcurrentMarkSweepThread::start_icms(); - assert(top < _icms_stop_limit, "Tautology"); - if (word_size < pointer_delta(_icms_stop_limit, top)) { - return _icms_stop_limit; - } - - // The allocation will cross both the _start and _stop limits, so do the - // stop notification also and return end(). - if (CMSTraceIncrementalMode) { - space->print_on(gclog_or_tty); - gclog_or_tty->stamp(); - gclog_or_tty->print_cr(" +stop limit top=" PTR_FORMAT - ", new limit=" PTR_FORMAT - " (" SIZE_FORMAT "%%)", - p2i(top), p2i(space->end()), - percent_of_space(space, space->end())); - } - ConcurrentMarkSweepThread::stop_icms(); - return space->end(); - } - - if (top <= _icms_stop_limit) { - if (CMSTraceIncrementalMode) { - space->print_on(gclog_or_tty); - gclog_or_tty->stamp(); - gclog_or_tty->print_cr(" stop limit top=" PTR_FORMAT - ", new limit=" PTR_FORMAT - " (" SIZE_FORMAT "%%)", - top, space->end(), - percent_of_space(space, space->end())); - } - ConcurrentMarkSweepThread::stop_icms(); - return space->end(); - } - - if (CMSTraceIncrementalMode) { - space->print_on(gclog_or_tty); - gclog_or_tty->stamp(); - gclog_or_tty->print_cr(" end limit top=" PTR_FORMAT - ", new limit=" PTR_FORMAT, - top, NULL); - } - } - - return NULL; -} - oop ConcurrentMarkSweepGeneration::promote(oop obj, size_t obj_size) { assert(obj_size == (size_t)obj->size(), "bad obj_size passed in"); // allocate, copy and if necessary update promoinfo -- @@ -1289,14 +1076,6 @@ } -HeapWord* -ConcurrentMarkSweepGeneration::allocation_limit_reached(Space* space, - HeapWord* top, - size_t word_sz) -{ - return collector()->allocation_limit_reached(space, top, word_sz); -} - // IMPORTANT: Notes on object size recognition in CMS. // --------------------------------------------------- // A block of storage in the CMS generation is always in @@ -1809,9 +1588,6 @@ // we want to do a foreground collection. _foregroundGCIsActive = true; - // Disable incremental mode during a foreground collection. - ICMSDisabler icms_disabler; - // release locks and wait for a notify from the background collector // releasing the locks in only necessary for phases which // do yields to improve the granularity of the collection. @@ -2135,7 +1911,7 @@ void CMSCollector::print_eden_and_survivor_chunk_arrays() { DefNewGeneration* dng = _young_gen->as_DefNewGeneration(); - EdenSpace* eden_space = dng->eden(); + ContiguousSpace* eden_space = dng->eden(); ContiguousSpace* from_space = dng->from(); ContiguousSpace* to_space = dng->to(); // Eden @@ -2783,10 +2559,6 @@ // _cmsGen->update_counters(cms_used); - if (CMSIncrementalMode) { - icms_update_allocation_limits(); - } - bitMapLock()->unlock(); releaseFreelistLocks(); @@ -4272,12 +4044,10 @@ assert_lock_strong(_bit_map_lock); _bit_map_lock->unlock(); ConcurrentMarkSweepThread::desynchronize(true); - ConcurrentMarkSweepThread::acknowledge_yield_request(); _collector->stopTimer(); if (PrintCMSStatistics != 0) { _collector->incrementYields(); } - _collector->icms_wait(); // It is possible for whichever thread initiated the yield request // not to get a chance to wake up and take the bitmap lock between @@ -4307,7 +4077,6 @@ ConcurrentMarkSweepThread::should_yield() && !CMSCollector::foregroundGCIsActive(); ++i) { os::sleep(Thread::current(), 1, false); - ConcurrentMarkSweepThread::acknowledge_yield_request(); } ConcurrentMarkSweepThread::synchronize(true); @@ -5238,7 +5007,7 @@ void CMSParMarkTask::work_on_young_gen_roots(uint worker_id, OopsInGenClosure* cl) { DefNewGeneration* dng = _collector->_young_gen->as_DefNewGeneration(); - EdenSpace* eden_space = dng->eden(); + ContiguousSpace* eden_space = dng->eden(); ContiguousSpace* from_space = dng->from(); ContiguousSpace* to_space = dng->to(); @@ -5410,7 +5179,7 @@ while (!pst->is_task_claimed(/* reference */ nth_task)) { // We claimed task # nth_task; compute its boundaries. if (chunk_top == 0) { // no samples were taken - assert(nth_task == 0 && n_tasks == 1, "Can have only 1 EdenSpace task"); + assert(nth_task == 0 && n_tasks == 1, "Can have only 1 eden task"); start = space->bottom(); end = space->top(); } else if (nth_task == 0) { @@ -5788,7 +5557,7 @@ // process_roots (which currently doesn't know how to // parallelize such a scan), but rather will be broken up into // a set of parallel tasks (via the sampling that the [abortable] - // preclean phase did of EdenSpace, plus the [two] tasks of + // preclean phase did of eden, plus the [two] tasks of // scanning the [two] survivor spaces. Further fine-grain // parallelization of the scanning of the survivor spaces // themselves, and of precleaning of the younger gen itself @@ -6474,19 +6243,16 @@ assert_lock_strong(bitMapLock()); bitMapLock()->unlock(); ConcurrentMarkSweepThread::desynchronize(true); - ConcurrentMarkSweepThread::acknowledge_yield_request(); stopTimer(); if (PrintCMSStatistics != 0) { incrementYields(); } - icms_wait(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && ConcurrentMarkSweepThread::should_yield() && !CMSCollector::foregroundGCIsActive(); ++i) { os::sleep(Thread::current(), 1, false); - ConcurrentMarkSweepThread::acknowledge_yield_request(); } ConcurrentMarkSweepThread::synchronize(true); @@ -6509,10 +6275,6 @@ _collectorState = Idling; } - // Stop incremental mode after a cycle completes, so that any future cycles - // are triggered by allocation. - stop_icms(); - NOT_PRODUCT( if (RotateCMSCollectionTypes) { _cmsGen->rotate_debug_collection_type(); @@ -6964,12 +6726,10 @@ _bit_map->lock()->unlock(); _freelistLock->unlock(); ConcurrentMarkSweepThread::desynchronize(true); - ConcurrentMarkSweepThread::acknowledge_yield_request(); _collector->stopTimer(); if (PrintCMSStatistics != 0) { _collector->incrementYields(); } - _collector->icms_wait(); // See the comment in coordinator_yield() for (unsigned i = 0; @@ -6978,7 +6738,6 @@ !CMSCollector::foregroundGCIsActive(); ++i) { os::sleep(Thread::current(), 1, false); - ConcurrentMarkSweepThread::acknowledge_yield_request(); } ConcurrentMarkSweepThread::synchronize(true); @@ -7124,19 +6883,16 @@ _bitMap->lock()->unlock(); _freelistLock->unlock(); ConcurrentMarkSweepThread::desynchronize(true); - ConcurrentMarkSweepThread::acknowledge_yield_request(); _collector->stopTimer(); if (PrintCMSStatistics != 0) { _collector->incrementYields(); } - _collector->icms_wait(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && ConcurrentMarkSweepThread::should_yield() && !CMSCollector::foregroundGCIsActive(); ++i) { os::sleep(Thread::current(), 1, false); - ConcurrentMarkSweepThread::acknowledge_yield_request(); } ConcurrentMarkSweepThread::synchronize(true); @@ -7196,19 +6952,16 @@ // Relinquish the bit map lock _bit_map->lock()->unlock(); ConcurrentMarkSweepThread::desynchronize(true); - ConcurrentMarkSweepThread::acknowledge_yield_request(); _collector->stopTimer(); if (PrintCMSStatistics != 0) { _collector->incrementYields(); } - _collector->icms_wait(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && ConcurrentMarkSweepThread::should_yield() && !CMSCollector::foregroundGCIsActive(); ++i) { os::sleep(Thread::current(), 1, false); - ConcurrentMarkSweepThread::acknowledge_yield_request(); } ConcurrentMarkSweepThread::synchronize(true); @@ -7354,19 +7107,16 @@ assert_lock_strong(_bitMap->lock()); _bitMap->lock()->unlock(); ConcurrentMarkSweepThread::desynchronize(true); - ConcurrentMarkSweepThread::acknowledge_yield_request(); _collector->stopTimer(); if (PrintCMSStatistics != 0) { _collector->incrementYields(); } - _collector->icms_wait(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && ConcurrentMarkSweepThread::should_yield() && !CMSCollector::foregroundGCIsActive(); ++i) { os::sleep(Thread::current(), 1, false); - ConcurrentMarkSweepThread::acknowledge_yield_request(); } ConcurrentMarkSweepThread::synchronize(true); @@ -7388,7 +7138,7 @@ _finger = ptr + obj->size(); assert(_finger > ptr, "we just incremented it above"); // On large heaps, it may take us some time to get through - // the marking phase (especially if running iCMS). During + // the marking phase. During // this time it's possible that a lot of mutations have // accumulated in the card table and the mod union table -- // these mutation records are redundant until we have @@ -7505,7 +7255,7 @@ _finger = ptr + obj->size(); assert(_finger > ptr, "we just incremented it above"); // On large heaps, it may take us some time to get through - // the marking phase (especially if running iCMS). During + // the marking phase. During // this time it's possible that a lot of mutations have // accumulated in the card table and the mod union table -- // these mutation records are redundant until we have @@ -7994,20 +7744,16 @@ bml->unlock(); ConcurrentMarkSweepThread::desynchronize(true); - ConcurrentMarkSweepThread::acknowledge_yield_request(); - _collector->stopTimer(); if (PrintCMSStatistics != 0) { _collector->incrementYields(); } - _collector->icms_wait(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && ConcurrentMarkSweepThread::should_yield() && !CMSCollector::foregroundGCIsActive(); ++i) { os::sleep(Thread::current(), 1, false); - ConcurrentMarkSweepThread::acknowledge_yield_request(); } ConcurrentMarkSweepThread::synchronize(true); @@ -8675,19 +8421,16 @@ _bitMap->lock()->unlock(); _freelistLock->unlock(); ConcurrentMarkSweepThread::desynchronize(true); - ConcurrentMarkSweepThread::acknowledge_yield_request(); _collector->stopTimer(); if (PrintCMSStatistics != 0) { _collector->incrementYields(); } - _collector->icms_wait(); // See the comment in coordinator_yield() for (unsigned i = 0; i < CMSYieldSleepCount && ConcurrentMarkSweepThread::should_yield() && !CMSCollector::foregroundGCIsActive(); ++i) { os::sleep(Thread::current(), 1, false); - ConcurrentMarkSweepThread::acknowledge_yield_request(); } ConcurrentMarkSweepThread::synchronize(true); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -356,7 +356,6 @@ size_t _gc0_promoted; // bytes promoted per gc0 double _cms_duration; double _cms_duration_pre_sweep; // time from initiation to start of sweep - double _cms_duration_per_mb; double _cms_period; size_t _cms_allocated; // bytes of direct allocation per gc0 period @@ -383,17 +382,7 @@ unsigned int _valid_bits; - unsigned int _icms_duty_cycle; // icms duty cycle (0-100). - protected: - - // Return a duty cycle that avoids wild oscillations, by limiting the amount - // of change between old_duty_cycle and new_duty_cycle (the latter is treated - // as a recommended value). - static unsigned int icms_damped_duty_cycle(unsigned int old_duty_cycle, - unsigned int new_duty_cycle); - unsigned int icms_update_duty_cycle_impl(); - // In support of adjusting of cms trigger ratios based on history // of concurrent mode failure. double cms_free_adjustment_factor(size_t free) const; @@ -426,7 +415,6 @@ size_t gc0_promoted() const { return _gc0_promoted; } double cms_period() const { return _cms_period; } double cms_duration() const { return _cms_duration; } - double cms_duration_per_mb() const { return _cms_duration_per_mb; } size_t cms_allocated() const { return _cms_allocated; } size_t cms_used_at_gc0_end() const { return _cms_used_at_gc0_end;} @@ -458,12 +446,6 @@ // End of higher level statistics. - // Returns the cms incremental mode duty cycle, as a percentage (0-100). - unsigned int icms_duty_cycle() const { return _icms_duty_cycle; } - - // Update the duty cycle and return the new value. - unsigned int icms_update_duty_cycle(); - // Debugging. void print_on(outputStream* st) const PRODUCT_RETURN; void print() const { print_on(gclog_or_tty); } @@ -725,13 +707,6 @@ // Timing, allocation and promotion statistics, used for scheduling. CMSStats _stats; - // Allocation limits installed in the young gen, used only in - // CMSIncrementalMode. When an allocation in the young gen would cross one of - // these limits, the cms generation is notified and the cms thread is started - // or stopped, respectively. - HeapWord* _icms_start_limit; - HeapWord* _icms_stop_limit; - enum CMS_op_type { CMS_op_checkpointRootsInitial, CMS_op_checkpointRootsFinal @@ -867,10 +842,6 @@ // collector. bool waitForForegroundGC(); - // Incremental mode triggering: recompute the icms duty cycle and set the - // allocation limits in the young gen. - void icms_update_allocation_limits(); - size_t block_size_using_printezis_bits(HeapWord* addr) const; size_t block_size_if_printezis_bits(HeapWord* addr) const; HeapWord* next_card_start_after_block(HeapWord* addr) const; @@ -928,9 +899,6 @@ void promoted(bool par, HeapWord* start, bool is_obj_array, size_t obj_size); - HeapWord* allocation_limit_reached(Space* space, HeapWord* top, - size_t word_size); - void getFreelistLocks() const; void releaseFreelistLocks() const; bool haveFreelistLocks() const; @@ -1001,14 +969,6 @@ // Timers/stats for gc scheduling and incremental mode pacing. CMSStats& stats() { return _stats; } - // Convenience methods that check whether CMSIncrementalMode is enabled and - // forward to the corresponding methods in ConcurrentMarkSweepThread. - static void start_icms(); - static void stop_icms(); // Called at the end of the cms cycle. - static void disable_icms(); // Called before a foreground collection. - static void enable_icms(); // Called after a foreground collection. - void icms_wait(); // Called at yield points. - // Adaptive size policy AdaptiveSizePolicy* size_policy(); @@ -1211,9 +1171,6 @@ return allocate(size, tlab); } - // Incremental mode triggering. - HeapWord* allocation_limit_reached(Space* space, HeapWord* top, - size_t word_size); // Used by CMSStats to track direct allocation. The value is sampled and // reset after each young gen collection. diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -234,36 +234,6 @@ } } -inline void CMSCollector::start_icms() { - if (CMSIncrementalMode) { - ConcurrentMarkSweepThread::start_icms(); - } -} - -inline void CMSCollector::stop_icms() { - if (CMSIncrementalMode) { - ConcurrentMarkSweepThread::stop_icms(); - } -} - -inline void CMSCollector::disable_icms() { - if (CMSIncrementalMode) { - ConcurrentMarkSweepThread::disable_icms(); - } -} - -inline void CMSCollector::enable_icms() { - if (CMSIncrementalMode) { - ConcurrentMarkSweepThread::enable_icms(); - } -} - -inline void CMSCollector::icms_wait() { - if (CMSIncrementalMode) { - cmsThread()->icms_wait(); - } -} - inline void CMSCollector::save_sweep_limits() { _cmsGen->save_sweep_limit(); } @@ -363,12 +333,6 @@ _cms_duration = AdaptiveWeightedAverage::exp_avg(_cms_duration, cur_duration, _cms_alpha); - // Avoid division by 0. - const size_t cms_used_mb = MAX2(_cms_used_at_cms_begin / M, (size_t)1); - _cms_duration_per_mb = AdaptiveWeightedAverage::exp_avg(_cms_duration_per_mb, - cur_duration / cms_used_mb, - _cms_alpha); - _cms_end_time.update(); _cms_alpha = _saved_alpha; _allow_duty_cycle_reduction = true; @@ -400,15 +364,6 @@ return (gc0_promoted() + cms_allocated()) / gc0_period(); } -inline unsigned int CMSStats::icms_update_duty_cycle() { - // Update the duty cycle only if pacing is enabled and the stats are valid - // (after at least one young gen gc and one cms cycle have completed). - if (CMSIncrementalPacing && valid()) { - return icms_update_duty_cycle_impl(); - } - return _icms_duty_cycle; -} - inline void ConcurrentMarkSweepGeneration::save_sweep_limit() { cmsSpace()->save_sweep_limit(); } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -49,13 +49,6 @@ int ConcurrentMarkSweepThread::_CMS_flag = CMS_nil; volatile jint ConcurrentMarkSweepThread::_pending_yields = 0; -volatile jint ConcurrentMarkSweepThread::_pending_decrements = 0; - -volatile jint ConcurrentMarkSweepThread::_icms_disabled = 0; -volatile bool ConcurrentMarkSweepThread::_should_run = false; -// When icms is enabled, the icms thread is stopped until explicitly -// started. -volatile bool ConcurrentMarkSweepThread::_should_stop = true; SurrogateLockerThread* ConcurrentMarkSweepThread::_slt = NULL; @@ -99,7 +92,6 @@ } } _sltMonitor = SLT_lock; - assert(!CMSIncrementalMode || icms_is_enabled(), "Error"); } void ConcurrentMarkSweepThread::run() { @@ -184,11 +176,6 @@ } void ConcurrentMarkSweepThread::stop() { - if (CMSIncrementalMode) { - // Disable incremental mode and wake up the thread so it notices the change. - disable_icms(); - start_icms(); - } // it is ok to take late safepoints here, if needed { MutexLockerEx x(Terminator_lock); @@ -387,23 +374,13 @@ void ConcurrentMarkSweepThread::sleepBeforeNextCycle() { while (!_should_terminate) { - if (CMSIncrementalMode) { - icms_wait(); - if(CMSWaitDuration >= 0) { - // Wait until the next synchronous GC, a concurrent full gc - // request or a timeout, whichever is earlier. - wait_on_cms_lock_for_scavenge(CMSWaitDuration); - } - return; + if(CMSWaitDuration >= 0) { + // Wait until the next synchronous GC, a concurrent full gc + // request or a timeout, whichever is earlier. + wait_on_cms_lock_for_scavenge(CMSWaitDuration); } else { - if(CMSWaitDuration >= 0) { - // Wait until the next synchronous GC, a concurrent full gc - // request or a timeout, whichever is earlier. - wait_on_cms_lock_for_scavenge(CMSWaitDuration); - } else { - // Wait until any cms_lock event or check interval not to call shouldConcurrentCollect permanently - wait_on_cms_lock(CMSCheckInterval); - } + // Wait until any cms_lock event or check interval not to call shouldConcurrentCollect permanently + wait_on_cms_lock(CMSCheckInterval); } // Check if we should start a CMS collection cycle if (_collector->shouldConcurrentCollect()) { @@ -414,42 +391,6 @@ } } -// Incremental CMS -void ConcurrentMarkSweepThread::start_icms() { - assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking"); - MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag); - trace_state("start_icms"); - _should_run = true; - iCMS_lock->notify_all(); -} - -void ConcurrentMarkSweepThread::stop_icms() { - assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking"); - MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag); - if (!_should_stop) { - trace_state("stop_icms"); - _should_stop = true; - _should_run = false; - asynchronous_yield_request(); - iCMS_lock->notify_all(); - } -} - -void ConcurrentMarkSweepThread::icms_wait() { - assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking"); - if (_should_stop && icms_is_enabled()) { - MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag); - trace_state("pause_icms"); - _collector->stats().stop_cms_timer(); - while(!_should_run && icms_is_enabled()) { - iCMS_lock->wait(Mutex::_no_safepoint_check_flag); - } - _collector->stats().start_cms_timer(); - _should_stop = false; - trace_state("pause_icms end"); - } -} - // Note: this method, although exported by the ConcurrentMarkSweepThread, // which is a non-JavaThread, can only be called by a JavaThread. // Currently this is done at vm creation time (post-vm-init) by the diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -64,20 +64,11 @@ static bool clear_CMS_flag(int b) { return (_CMS_flag &= ~b) != 0; } void sleepBeforeNextCycle(); - // CMS thread should yield for a young gen collection, direct allocation, - // and iCMS activity. + // CMS thread should yield for a young gen collection and direct allocations static char _pad_1[64 - sizeof(jint)]; // prevent cache-line sharing static volatile jint _pending_yields; - static volatile jint _pending_decrements; // decrements to _pending_yields static char _pad_2[64 - sizeof(jint)]; // prevent cache-line sharing - // Tracing messages, enabled by CMSTraceThreadState. - static inline void trace_state(const char* desc); - - static volatile int _icms_disabled; // a counter to track #iCMS disable & enable - static volatile bool _should_run; // iCMS may run - static volatile bool _should_stop; // iCMS should stop - // debugging void verify_ok_to_terminate() const PRODUCT_RETURN; @@ -135,44 +126,13 @@ void wait_on_cms_lock_for_scavenge(long t_millis); // The CMS thread will yield during the work portion of its cycle - // only when requested to. Both synchronous and asychronous requests - // are provided: - // (1) A synchronous request is used for young gen collections and - // for direct allocations. The requesting thread increments - // _pending_yields at the beginning of an operation, and decrements - // _pending_yields when that operation is completed. - // In turn, the CMS thread yields when _pending_yields is positive, - // and continues to yield until the value reverts to 0. - // (2) An asynchronous request, on the other hand, is used by iCMS - // for the stop_icms() operation. A single yield satisfies all of - // the outstanding asynch yield requests, of which there may - // occasionally be several in close succession. To accomplish - // this, an asynch-requesting thread atomically increments both - // _pending_yields and _pending_decrements. An asynchr requesting - // thread does not wait and "acknowledge" completion of an operation - // and deregister the request, like the synchronous version described - // above does. In turn, after yielding, the CMS thread decrements both - // _pending_yields and _pending_decrements by the value seen in - // _pending_decrements before the decrement. - // NOTE: The above scheme is isomorphic to having two request counters, - // one for async requests and one for sync requests, and for the CMS thread - // to check the sum of the two counters to decide whether it should yield - // and to clear only the async counter when it yields. However, it turns out - // to be more efficient for CMS code to just check a single counter - // _pending_yields that holds the sum (of both sync and async requests), and - // a second counter _pending_decrements that only holds the async requests, - // for greater efficiency, since in a typical CMS run, there are many more - // potential (i.e. static) yield points than there are actual - // (i.e. dynamic) yields because of requests, which are few and far between. - // - // Note that, while "_pending_yields >= _pending_decrements" is an invariant, - // we cannot easily test that invariant, since the counters are manipulated via - // atomic instructions without explicit locking and we cannot read - // the two counters atomically together: one suggestion is to - // use (for example) 16-bit counters so as to be able to read the - // two counters atomically even on 32-bit platforms. Notice that - // the second assert in acknowledge_yield_request() below does indeed - // check a form of the above invariant, albeit indirectly. + // only when requested to. + // A synchronous request is used for young gen collections and + // for direct allocations. The requesting thread increments + // _pending_yields at the beginning of an operation, and decrements + // _pending_yields when that operation is completed. + // In turn, the CMS thread yields when _pending_yields is positive, + // and continues to yield until the value reverts to 0. static void increment_pending_yields() { Atomic::inc(&_pending_yields); @@ -182,67 +142,9 @@ Atomic::dec(&_pending_yields); assert(_pending_yields >= 0, "can't be negative"); } - static void asynchronous_yield_request() { - assert(CMSIncrementalMode, "Currently only used w/iCMS"); - increment_pending_yields(); - Atomic::inc(&_pending_decrements); - assert(_pending_decrements >= 0, "can't be negative"); - } - static void acknowledge_yield_request() { - jint decrement = _pending_decrements; - if (decrement > 0) { - assert(CMSIncrementalMode, "Currently only used w/iCMS"); - // Order important to preserve: _pending_yields >= _pending_decrements - Atomic::add(-decrement, &_pending_decrements); - Atomic::add(-decrement, &_pending_yields); - assert(_pending_decrements >= 0, "can't be negative"); - assert(_pending_yields >= 0, "can't be negative"); - } - } static bool should_yield() { return _pending_yields > 0; } - - // CMS incremental mode. - static void start_icms(); // notify thread to start a quantum of work - static void stop_icms(); // request thread to stop working - void icms_wait(); // if asked to stop, wait until notified to start - - // Incremental mode is enabled globally by the flag CMSIncrementalMode. It - // must also be enabled/disabled dynamically to allow foreground collections. -#define ICMS_ENABLING_ASSERT \ - assert((CMSIncrementalMode && _icms_disabled >= 0) || \ - (!CMSIncrementalMode && _icms_disabled <= 0), "Error") - - static inline void enable_icms() { - ICMS_ENABLING_ASSERT; - Atomic::dec(&_icms_disabled); - } - static inline void disable_icms() { - ICMS_ENABLING_ASSERT; - Atomic::inc(&_icms_disabled); - } - static inline bool icms_is_disabled() { - ICMS_ENABLING_ASSERT; - return _icms_disabled > 0; - } - static inline bool icms_is_enabled() { - return !icms_is_disabled(); - } }; -inline void ConcurrentMarkSweepThread::trace_state(const char* desc) { - if (CMSTraceThreadState) { - char buf[128]; - TimeStamp& ts = gclog_or_tty->time_stamp(); - if (!ts.is_updated()) { - ts.update(); - } - jio_snprintf(buf, sizeof(buf), " [%.3f: CMSThread %s] ", - ts.seconds(), desc); - buf[sizeof(buf) - 1] = '\0'; - gclog_or_tty->print("%s", buf); - } -} - // For scoped increment/decrement of (synchronous) yield requests class CMSSynchronousYieldRequest: public StackObj { public: diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -207,12 +207,6 @@ MutexLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag); assert(_full_gc_count_before <= gch->total_full_collections(), "Error"); if (gch->total_full_collections() == _full_gc_count_before) { - // Disable iCMS until the full collection is done, and - // remember that we did so. - CMSCollector::disable_icms(); - _disabled_icms = true; - // In case CMS thread was in icms_wait(), wake it up. - CMSCollector::start_icms(); // Nudge the CMS thread to start a concurrent collection. CMSCollector::request_full_gc(_full_gc_count_before, _gc_cause); } else { @@ -276,8 +270,4 @@ FullGCCount_lock->wait(Mutex::_no_safepoint_check_flag); } } - // Enable iCMS back if we disabled it earlier. - if (_disabled_icms) { - CMSCollector::enable_icms(); - } } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -128,13 +128,11 @@ // VM operation to invoke a concurrent collection of the heap as a // GenCollectedHeap heap. class VM_GenCollectFullConcurrent: public VM_GC_Operation { - bool _disabled_icms; public: VM_GenCollectFullConcurrent(unsigned int gc_count_before, unsigned int full_gc_count_before, GCCause::Cause gc_cause) - : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true /* full */), - _disabled_icms(false) + : VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true /* full */) { assert(FullGCCount_lock != NULL, "Error"); assert(UseAsyncConcMarkSweepGC, "Else will hang caller"); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -1248,7 +1248,7 @@ // The same as above but assume that the caller holds the Heap_lock. void collect_locked(GCCause::Cause cause); - virtual void copy_allocation_context_stats(const jint* contexts, + virtual bool copy_allocation_context_stats(const jint* contexts, jlong* totals, jbyte* accuracy, jint len); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap_ext.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap_ext.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap_ext.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -25,8 +25,9 @@ #include "precompiled.hpp" #include "gc_implementation/g1/g1CollectedHeap.hpp" -void G1CollectedHeap::copy_allocation_context_stats(const jint* contexts, +bool G1CollectedHeap::copy_allocation_context_stats(const jint* contexts, jlong* totals, jbyte* accuracy, jint len) { + return false; } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -1585,34 +1585,22 @@ } }; +uint G1CollectorPolicy::calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) { + assert(n_workers > 0, "Active gc workers should be greater than 0"); + const uint overpartition_factor = 4; + const uint min_chunk_size = MAX2(n_regions / n_workers, 1U); + return MAX2(n_regions / (n_workers * overpartition_factor), min_chunk_size); +} + void -G1CollectorPolicy::record_concurrent_mark_cleanup_end(int no_of_gc_threads) { +G1CollectorPolicy::record_concurrent_mark_cleanup_end(uint n_workers) { _collectionSetChooser->clear(); - uint region_num = _g1->num_regions(); - const uint OverpartitionFactor = 4; - uint WorkUnit; - // The use of MinChunkSize = 8 in the original code - // causes some assertion failures when the total number of - // region is less than 8. The code here tries to fix that. - // Should the original code also be fixed? - if (no_of_gc_threads > 0) { - const uint MinWorkUnit = MAX2(region_num / no_of_gc_threads, 1U); - WorkUnit = MAX2(region_num / (no_of_gc_threads * OverpartitionFactor), - MinWorkUnit); - } else { - assert(no_of_gc_threads > 0, - "The active gc workers should be greater than 0"); - // In a product build do something reasonable to avoid a crash. - const uint MinWorkUnit = MAX2(region_num / (uint) ParallelGCThreads, 1U); - WorkUnit = - MAX2(region_num / (uint) (ParallelGCThreads * OverpartitionFactor), - MinWorkUnit); - } - _collectionSetChooser->prepare_for_par_region_addition(_g1->num_regions(), - WorkUnit); - ParKnownGarbageTask parKnownGarbageTask(_collectionSetChooser, WorkUnit, (uint) no_of_gc_threads); - _g1->workers()->run_task(&parKnownGarbageTask); + uint n_regions = _g1->num_regions(); + uint chunk_size = calculate_parallel_work_chunk_size(n_workers, n_regions); + _collectionSetChooser->prepare_for_par_region_addition(n_regions, chunk_size); + ParKnownGarbageTask par_known_garbage_task(_collectionSetChooser, chunk_size, n_workers); + _g1->workers()->run_task(&par_known_garbage_task); _collectionSetChooser->sort_regions(); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -612,6 +612,10 @@ uint desired_min_length, uint desired_max_length); + // Calculate and return chunk size (in number of regions) for parallel + // concurrent mark cleanup. + uint calculate_parallel_work_chunk_size(uint n_workers, uint n_regions); + // Check whether a given young length (young_length) fits into the // given target pause time and whether the prediction for the amount // of objects to be copied for the given length will fit into the @@ -687,7 +691,7 @@ // Record start, end, and completion of cleanup. void record_concurrent_mark_cleanup_start(); - void record_concurrent_mark_cleanup_end(int no_of_gc_threads); + void record_concurrent_mark_cleanup_end(uint n_workers); void record_concurrent_mark_cleanup_completed(); // Records the information about the heap size for reporting in diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -97,13 +97,6 @@ FREE_C_HEAP_ARRAY(OopsInHeapRegionClosure*, _cset_rs_update_cl, mtGC); } -void CountNonCleanMemRegionClosure::do_MemRegion(MemRegion mr) { - if (_g1->is_in_g1_reserved(mr.start())) { - _n += (int) ((mr.byte_size() / CardTableModRefBS::card_size)); - if (_start_first == NULL) _start_first = mr.start(); - } -} - class ScanRSClosure : public HeapRegionClosure { size_t _cards_done, _cards; G1CollectedHeap* _g1h; @@ -303,15 +296,6 @@ _g1->iterate_dirty_card_closure(&into_cset_update_rs_cl, into_cset_dcq, false, worker_i); - // Now there should be no dirty cards. - if (G1RSLogCheckCardTable) { - CountNonCleanMemRegionClosure cl(_g1); - _ct_bs->mod_card_iterate(&cl); - // XXX This isn't true any more: keeping cards of young regions - // marked dirty broke it. Need some reasonable fix. - guarantee(cl.n() == 0, "Card table should be clean."); - } - _g1p->phase_times()->record_update_rs_time(worker_i, (os::elapsedTime() - start) * 1000.0); } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -151,19 +151,6 @@ } }; -class CountNonCleanMemRegionClosure: public MemRegionClosure { - G1CollectedHeap* _g1; - int _n; - HeapWord* _start_first; -public: - CountNonCleanMemRegionClosure(G1CollectedHeap* g1) : - _g1(g1), _n(0), _start_first(NULL) - {} - void do_MemRegion(MemRegion mr); - int n() { return _n; }; - HeapWord* start_first() { return _start_first; } -}; - class UpdateRSOopClosure: public ExtendedOopClosure { HeapRegion* _from; G1RemSet* _rs; diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -108,10 +108,6 @@ develop(bool, G1RSBarrierRegionFilter, true, \ "If true, generate region filtering code in RS barrier") \ \ - develop(bool, G1RSLogCheckCardTable, false, \ - "If true, verify that no dirty cards remain after RS log " \ - "processing.") \ - \ diagnostic(bool, G1PrintRegionLivenessInfo, false, \ "Prints the liveness information for all regions in the heap " \ "at the end of a marking cycle.") \ diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -960,6 +960,10 @@ verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy); } +void HeapRegion::prepare_for_compaction(CompactPoint* cp) { + scan_and_forward(this, cp); +} + // G1OffsetTableContigSpace code; copied from space.cpp. Hope this can go // away eventually. @@ -1043,12 +1047,6 @@ } } -#define block_is_always_obj(q) true -void G1OffsetTableContigSpace::prepare_for_compaction(CompactPoint* cp) { - SCAN_AND_FORWARD(cp, top, block_is_always_obj, block_size); -} -#undef block_is_always_obj - G1OffsetTableContigSpace:: G1OffsetTableContigSpace(G1BlockOffsetSharedArray* sharedOffsetArray, MemRegion mr) : diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -187,8 +187,6 @@ HeapWord* block_start(const void* p); HeapWord* block_start_const(const void* p) const; - void prepare_for_compaction(CompactPoint* cp); - // Add offset table update. virtual HeapWord* allocate(size_t word_size); HeapWord* par_allocate(size_t word_size); @@ -210,6 +208,9 @@ class HeapRegion: public G1OffsetTableContigSpace { friend class VMStructs; + // Allow scan_and_forward to call (private) overrides for auxiliary functions on this class + template + friend void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp); private: // The remembered set for this region. @@ -219,6 +220,20 @@ G1BlockOffsetArrayContigSpace* offsets() { return &_offsets; } + // Auxiliary functions for scan_and_forward support. + // See comments for CompactibleSpace for more information. + inline HeapWord* scan_limit() const { + return top(); + } + + inline bool scanned_block_is_obj(const HeapWord* addr) const { + return true; // Always true, since scan_limit is top + } + + inline size_t scanned_block_size(const HeapWord* addr) const { + return HeapRegion::block_size(addr); // Avoid virtual call + } + protected: // The index of this region in the heap region sequence. uint _hrm_index; @@ -340,6 +355,9 @@ // and the amount of unallocated words if called on top() size_t block_size(const HeapWord* p) const; + // Override for scan_and_forward support. + void prepare_for_compaction(CompactPoint* cp); + inline HeapWord* par_allocate_no_bot_updates(size_t word_size); inline HeapWord* allocate_no_bot_updates(size_t word_size); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -426,11 +426,19 @@ mtGC); G1BlockOffsetSharedArray oa(heap, bot_storage); bot_storage->commit_regions(0, num_regions_in_test); - HeapRegion hr0(0, &oa, heap); - HeapRegion hr1(1, &oa, heap); - HeapRegion hr2(2, &oa, heap); - HeapRegion hr3(3, &oa, heap); - HeapRegion hr4(4, &oa, heap); + + // Set up memory regions for the heap regions. + MemRegion mr0(heap.start(), HeapRegion::GrainWords); + MemRegion mr1(mr0.end(), HeapRegion::GrainWords); + MemRegion mr2(mr1.end(), HeapRegion::GrainWords); + MemRegion mr3(mr2.end(), HeapRegion::GrainWords); + MemRegion mr4(mr3.end(), HeapRegion::GrainWords); + + HeapRegion hr0(0, &oa, mr0); + HeapRegion hr1(1, &oa, mr1); + HeapRegion hr2(2, &oa, mr2); + HeapRegion hr3(3, &oa, mr3); + HeapRegion hr4(4, &oa, mr4); l.add_ordered(&hr1); l.add_ordered(&hr0); l.add_ordered(&hr3); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp --- a/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_implementation/shared/markSweep.inline.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -27,6 +27,7 @@ #include "gc_implementation/shared/markSweep.hpp" #include "gc_interface/collectedHeap.hpp" +#include "oops/markOop.inline.hpp" #include "utilities/stack.inline.hpp" #include "utilities/macros.hpp" #if INCLUDE_ALL_GCS diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/gc_interface/collectedHeap.hpp --- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -644,10 +644,13 @@ // For each context in contexts, set the corresponding entries in the totals // and accuracy arrays to the current values held by the statistics. Each // array should be of length len. - virtual void copy_allocation_context_stats(const jint* contexts, + // Returns true if there are more stats available. + virtual bool copy_allocation_context_stats(const jint* contexts, jlong* totals, jbyte* accuracy, - jint len) { } + jint len) { + return false; + } /////////////// Unit tests /////////////// diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/interpreter/bytecodes.hpp --- a/hotspot/src/share/vm/interpreter/bytecodes.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/interpreter/bytecodes.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -401,8 +401,10 @@ static bool is_astore (Code code) { return (code == _astore || code == _astore_0 || code == _astore_1 || code == _astore_2 || code == _astore_3); } + static bool is_const (Code code) { return (_aconst_null <= code && code <= _ldc2_w); } static bool is_zero_const (Code code) { return (code == _aconst_null || code == _iconst_0 || code == _fconst_0 || code == _dconst_0); } + static bool is_return (Code code) { return (_ireturn <= code && code <= _return); } static bool is_invoke (Code code) { return (_invokevirtual <= code && code <= _invokedynamic); } static bool has_receiver (Code code) { assert(is_invoke(code), ""); return code == _invokevirtual || code == _invokespecial || diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/memory/collectorPolicy.hpp --- a/hotspot/src/share/vm/memory/collectorPolicy.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/memory/collectorPolicy.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -189,11 +189,6 @@ return CollectorPolicy::CollectorPolicyKind; } - // Returns true if a collector has eden space with soft end. - virtual bool has_soft_ended_eden() { - return false; - } - // Do any updates required to global flags that are due to heap initialization // changes virtual void post_heap_initialize() = 0; diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/memory/defNewGeneration.cpp --- a/hotspot/src/share/vm/memory/defNewGeneration.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/memory/defNewGeneration.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -194,11 +194,7 @@ (HeapWord*)_virtual_space.high()); Universe::heap()->barrier_set()->resize_covered_region(cmr); - if (GenCollectedHeap::heap()->collector_policy()->has_soft_ended_eden()) { - _eden_space = new ConcEdenSpace(this); - } else { - _eden_space = new EdenSpace(this); - } + _eden_space = new ContiguousSpace(); _from_space = new ContiguousSpace(); _to_space = new ContiguousSpace(); @@ -1038,38 +1034,12 @@ if (CMSEdenChunksRecordAlways && _next_gen != NULL) { _next_gen->sample_eden_chunk(); } - return result; - } - do { - HeapWord* old_limit = eden()->soft_end(); - if (old_limit < eden()->end()) { - // Tell the next generation we reached a limit. - HeapWord* new_limit = - next_gen()->allocation_limit_reached(eden(), eden()->top(), word_size); - if (new_limit != NULL) { - Atomic::cmpxchg_ptr(new_limit, eden()->soft_end_addr(), old_limit); - } else { - assert(eden()->soft_end() == eden()->end(), - "invalid state after allocation_limit_reached returned null"); - } - } else { - // The allocation failed and the soft limit is equal to the hard limit, - // there are no reasons to do an attempt to allocate - assert(old_limit == eden()->end(), "sanity check"); - break; - } - // Try to allocate until succeeded or the soft limit can't be adjusted - result = eden()->par_allocate(word_size); - } while (result == NULL); - - // 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. - // allocate_from_space can't be inlined because that would introduce a - // circular dependency at compile time. - if (result == NULL) { + } 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. + // allocate_from_space can't be inlined because that would introduce a + // circular dependency at compile time. result = allocate_from_space(word_size); - } else if (CMSEdenChunksRecordAlways && _next_gen != NULL) { - _next_gen->sample_eden_chunk(); } return result; } @@ -1083,11 +1053,6 @@ return res; } -void DefNewGeneration::gc_prologue(bool full) { - // Ensure that _end and _soft_end are the same in eden space. - eden()->set_soft_end(eden()->end()); -} - size_t DefNewGeneration::tlab_capacity() const { return eden()->capacity(); } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/memory/defNewGeneration.hpp --- a/hotspot/src/share/vm/memory/defNewGeneration.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/memory/defNewGeneration.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -32,7 +32,6 @@ #include "memory/generation.inline.hpp" #include "utilities/stack.hpp" -class EdenSpace; class ContiguousSpace; class ScanClosure; class STWGCTimer; @@ -132,7 +131,7 @@ void adjust_desired_tenuring_threshold(); // Spaces - EdenSpace* _eden_space; + ContiguousSpace* _eden_space; ContiguousSpace* _from_space; ContiguousSpace* _to_space; @@ -214,9 +213,9 @@ virtual Generation::Name kind() { return Generation::DefNew; } // Accessing spaces - EdenSpace* eden() const { return _eden_space; } - ContiguousSpace* from() const { return _from_space; } - ContiguousSpace* to() const { return _to_space; } + ContiguousSpace* eden() const { return _eden_space; } + ContiguousSpace* from() const { return _from_space; } + ContiguousSpace* to() const { return _to_space; } virtual CompactibleSpace* first_compaction_space() const; @@ -282,8 +281,6 @@ HeapWord* par_allocate(size_t word_size, bool is_tlab); - // Prologue & Epilogue - virtual void gc_prologue(bool full); virtual void gc_epilogue(bool full); // Save the tops for eden, from, and to diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/memory/generation.hpp --- a/hotspot/src/share/vm/memory/generation.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/memory/generation.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -265,14 +265,6 @@ // Like "allocate", but performs any necessary locking internally. virtual HeapWord* par_allocate(size_t word_size, bool is_tlab) = 0; - // A 'younger' gen has reached an allocation limit, and uses this to notify - // the next older gen. The return value is a new limit, or NULL if none. The - // caller must do the necessary locking. - virtual HeapWord* allocation_limit_reached(Space* space, HeapWord* top, - size_t word_size) { - return NULL; - } - // Some generation may offer a region for shared, contiguous allocation, // via inlined code (by exporting the address of the top and end fields // defining the extent of the contiguous allocation region.) diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/memory/metaspaceShared.cpp --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -715,15 +715,17 @@ if (class_list_path_len >= 3) { if (strcmp(class_list_path_str + class_list_path_len - 3, "lib") != 0) { if (class_list_path_len < JVM_MAXPATHLEN - 4) { - strncat(class_list_path_str, os::file_separator(), 1); - strncat(class_list_path_str, "lib", 3); + jio_snprintf(class_list_path_str + class_list_path_len, + sizeof(class_list_path_str) - class_list_path_len, + "%slib", os::file_separator()); + class_list_path_len += 4; } } } - class_list_path_len = (int)strlen(class_list_path_str); if (class_list_path_len < JVM_MAXPATHLEN - 10) { - strncat(class_list_path_str, os::file_separator(), 1); - strncat(class_list_path_str, "classlist", 9); + jio_snprintf(class_list_path_str + class_list_path_len, + sizeof(class_list_path_str) - class_list_path_len, + "%sclasslist", os::file_separator()); } class_list_path = class_list_path_str; } else { @@ -851,7 +853,7 @@ ik->link_class(THREAD); if (HAS_PENDING_EXCEPTION) { ResourceMark rm; - tty->print_cr("Preload Error: Verification failed for %s", + tty->print_cr("Preload Warning: Verification failed for %s", ik->external_name()); CLEAR_PENDING_EXCEPTION; ik->set_in_error_state(); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/memory/space.cpp --- a/hotspot/src/share/vm/memory/space.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/memory/space.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -438,52 +438,8 @@ } } -#define block_is_always_obj(q) true -#define obj_size(q) oop(q)->size() -#define adjust_obj_size(s) s - -void CompactibleSpace::prepare_for_compaction(CompactPoint* cp) { - SCAN_AND_FORWARD(cp, end, block_is_obj, block_size); -} - -// Faster object search. void ContiguousSpace::prepare_for_compaction(CompactPoint* cp) { - SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size); -} - -void Space::adjust_pointers() { - // adjust all the interior pointers to point at the new locations of objects - // Used by MarkSweep::mark_sweep_phase3() - - // First check to see if there is any work to be done. - if (used() == 0) { - return; // Nothing to do. - } - - // Otherwise... - HeapWord* q = bottom(); - HeapWord* t = end(); - - debug_only(HeapWord* prev_q = NULL); - while (q < t) { - if (oop(q)->is_gc_marked()) { - // q is alive - - // point all the oops to the new location - size_t size = oop(q)->adjust_pointers(); - - debug_only(prev_q = q); - - q += size; - } else { - // q is not a live object. But we're not in a compactible space, - // So we don't have live ranges. - debug_only(prev_q = q); - q += block_size(q); - assert(q > prev_q, "we should be moving forward through memory"); - } - } - assert(q == t, "just checking"); + scan_and_forward(this, cp); } void CompactibleSpace::adjust_pointers() { @@ -492,11 +448,11 @@ return; // Nothing to do. } - SCAN_AND_ADJUST_POINTERS(adjust_obj_size); + scan_and_adjust_pointers(this); } void CompactibleSpace::compact() { - SCAN_AND_COMPACT(obj_size); + scan_and_compact(this); } void Space::print_short() const { print_short_on(tty); } @@ -684,13 +640,12 @@ } // This version requires locking. -inline HeapWord* ContiguousSpace::allocate_impl(size_t size, - HeapWord* const end_value) { +inline HeapWord* ContiguousSpace::allocate_impl(size_t size) { assert(Heap_lock->owned_by_self() || (SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread()), "not locked"); HeapWord* obj = top(); - if (pointer_delta(end_value, obj) >= size) { + if (pointer_delta(end(), obj) >= size) { HeapWord* new_top = obj + size; set_top(new_top); assert(is_aligned(obj) && is_aligned(new_top), "checking alignment"); @@ -701,11 +656,10 @@ } // This version is lock-free. -inline HeapWord* ContiguousSpace::par_allocate_impl(size_t size, - HeapWord* const end_value) { +inline HeapWord* ContiguousSpace::par_allocate_impl(size_t size) { do { HeapWord* obj = top(); - if (pointer_delta(end_value, obj) >= size) { + if (pointer_delta(end(), obj) >= size) { HeapWord* new_top = obj + size; HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj); // result can be one of two: @@ -744,12 +698,12 @@ // Requires locking. HeapWord* ContiguousSpace::allocate(size_t size) { - return allocate_impl(size, end()); + return allocate_impl(size); } // Lock-free. HeapWord* ContiguousSpace::par_allocate(size_t size) { - return par_allocate_impl(size, end()); + return par_allocate_impl(size); } void ContiguousSpace::allocate_temporary_filler(int factor) { @@ -784,49 +738,6 @@ } } -void EdenSpace::clear(bool mangle_space) { - ContiguousSpace::clear(mangle_space); - set_soft_end(end()); -} - -// Requires locking. -HeapWord* EdenSpace::allocate(size_t size) { - return allocate_impl(size, soft_end()); -} - -// Lock-free. -HeapWord* EdenSpace::par_allocate(size_t size) { - return par_allocate_impl(size, soft_end()); -} - -HeapWord* ConcEdenSpace::par_allocate(size_t size) -{ - do { - // The invariant is top() should be read before end() because - // top() can't be greater than end(), so if an update of _soft_end - // occurs between 'end_val = end();' and 'top_val = top();' top() - // also can grow up to the new end() and the condition - // 'top_val > end_val' is true. To ensure the loading order - // OrderAccess::loadload() is required after top() read. - HeapWord* obj = top(); - OrderAccess::loadload(); - if (pointer_delta(*soft_end_addr(), obj) >= size) { - HeapWord* new_top = obj + size; - HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj); - // result can be one of two: - // the old top value: the exchange succeeded - // otherwise: the new value of the top is returned. - if (result == obj) { - assert(is_aligned(obj) && is_aligned(new_top), "checking alignment"); - return obj; - } - } else { - return NULL; - } - } while (true); -} - - HeapWord* OffsetTableContigSpace::initialize_threshold() { return _offsets.initialize_threshold(); } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/memory/space.hpp --- a/hotspot/src/share/vm/memory/space.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/memory/space.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -41,19 +41,6 @@ // implementations for keeping track of free and used space, // for iterating over objects and free blocks, etc. -// Here's the Space hierarchy: -// -// - Space -- an abstract base class describing a heap area -// - CompactibleSpace -- a space supporting compaction -// - CompactibleFreeListSpace -- (used for CMS generation) -// - ContiguousSpace -- a compactible space in which all free space -// is contiguous -// - EdenSpace -- contiguous space used as nursery -// - ConcEdenSpace -- contiguous space with a 'soft end safe' allocation -// - OffsetTableContigSpace -- contiguous space with a block offset array -// that allows "fast" block_start calls -// - TenuredSpace -- (used for TenuredGeneration) - // Forward decls. class Space; class BlockOffsetArray; @@ -238,7 +225,7 @@ // Mark-sweep-compact support: all spaces can update pointers to objects // moving as a part of compaction. - virtual void adjust_pointers(); + virtual void adjust_pointers() = 0; // PrintHeapAtGC support virtual void print() const; @@ -339,7 +326,36 @@ // necessarily, a space that is normally contiguous. But, for example, a // free-list-based space whose normal collection is a mark-sweep without // compaction could still support compaction in full GC's. - +// +// The compaction operations are implemented by the +// scan_and_{adjust_pointers,compact,forward} function templates. +// The following are, non-virtual, auxiliary functions used by these function templates: +// - scan_limit() +// - scanned_block_is_obj() +// - scanned_block_size() +// - adjust_obj_size() +// - obj_size() +// These functions are to be used exclusively by the scan_and_* function templates, +// and must be defined for all (non-abstract) subclasses of CompactibleSpace. +// +// NOTE: Any subclasses to CompactibleSpace wanting to change/define the behavior +// in any of the auxiliary functions must also override the corresponding +// prepare_for_compaction/adjust_pointers/compact functions using them. +// If not, such changes will not be used or have no effect on the compaction operations. +// +// This translates to the following dependencies: +// Overrides/definitions of +// - scan_limit +// - scanned_block_is_obj +// - scanned_block_size +// require override/definition of prepare_for_compaction(). +// Similar dependencies exist between +// - adjust_obj_size and adjust_pointers() +// - obj_size and compact(). +// +// Additionally, this also means that changes to block_size() or block_is_obj() that +// should be effective during the compaction operations must provide a corresponding +// definition of scanned_block_size/scanned_block_is_obj respectively. class CompactibleSpace: public Space { friend class VMStructs; friend class CompactibleFreeListSpace; @@ -347,6 +363,15 @@ HeapWord* _compaction_top; CompactibleSpace* _next_compaction_space; + // Auxiliary functions for scan_and_{forward,adjust_pointers,compact} support. + inline size_t adjust_obj_size(size_t size) const { + return size; + } + + inline size_t obj_size(const HeapWord* addr) const { + return oop(addr)->size(); + } + public: CompactibleSpace() : _compaction_top(NULL), _next_compaction_space(NULL) {} @@ -390,7 +415,7 @@ // "cp->compaction_space" up-to-date. Offset tables may be updated in // this phase as if the final copy had occurred; if so, "cp->threshold" // indicates when the next such action should be taken. - virtual void prepare_for_compaction(CompactPoint* cp); + virtual void prepare_for_compaction(CompactPoint* cp) = 0; // MarkSweep support phase3 virtual void adjust_pointers(); // MarkSweep support phase4 @@ -449,6 +474,25 @@ // words remaining after this operation. bool insert_deadspace(size_t& allowed_deadspace_words, HeapWord* q, size_t word_len); + + // Below are template functions for scan_and_* algorithms (avoiding virtual calls). + // The space argument should be a subclass of CompactibleSpace, implementing + // scan_limit(), scanned_block_is_obj(), and scanned_block_size(), + // and possibly also overriding obj_size(), and adjust_obj_size(). + // These functions should avoid virtual calls whenever possible. + + // Frequently calls adjust_obj_size(). + template + static inline void scan_and_adjust_pointers(SpaceType* space); + + // Frequently calls obj_size(). + template + static inline void scan_and_compact(SpaceType* space); + + // Frequently calls scanned_block_is_obj() and scanned_block_size(). + // Requires the scan_limit() function. + template + static inline void scan_and_forward(SpaceType* space, CompactPoint* cp); }; class GenSpaceMangler; @@ -458,6 +502,25 @@ class ContiguousSpace: public CompactibleSpace { friend class OneContigSpaceCardGeneration; friend class VMStructs; + // Allow scan_and_forward function to call (private) overrides for auxiliary functions on this class + template + friend void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp); + + private: + // Auxiliary functions for scan_and_forward support. + // See comments for CompactibleSpace for more information. + inline HeapWord* scan_limit() const { + return top(); + } + + inline bool scanned_block_is_obj(const HeapWord* addr) const { + return true; // Always true, since scan_limit is top + } + + inline size_t scanned_block_size(const HeapWord* addr) const { + return oop(addr)->size(); + } + protected: HeapWord* _top; HeapWord* _concurrent_iteration_safe_limit; @@ -467,8 +530,8 @@ GenSpaceMangler* mangler() { return _mangler; } // Allocation helpers (return NULL if full). - inline HeapWord* allocate_impl(size_t word_size, HeapWord* end_value); - inline HeapWord* par_allocate_impl(size_t word_size, HeapWord* end_value); + inline HeapWord* allocate_impl(size_t word_size); + inline HeapWord* par_allocate_impl(size_t word_size); public: ContiguousSpace(); @@ -622,7 +685,6 @@ // Used to increase collection frequency. "factor" of 0 means entire // space. void allocate_temporary_filler(int factor); - }; @@ -685,56 +747,6 @@ {} }; - -// Class EdenSpace describes eden-space in new generation. - -class DefNewGeneration; - -class EdenSpace : public ContiguousSpace { - friend class VMStructs; - private: - DefNewGeneration* _gen; - - // _soft_end is used as a soft limit on allocation. As soft limits are - // reached, the slow-path allocation code can invoke other actions and then - // adjust _soft_end up to a new soft limit or to end(). - HeapWord* _soft_end; - - public: - EdenSpace(DefNewGeneration* gen) : - _gen(gen), _soft_end(NULL) {} - - // Get/set just the 'soft' limit. - HeapWord* soft_end() { return _soft_end; } - HeapWord** soft_end_addr() { return &_soft_end; } - void set_soft_end(HeapWord* value) { _soft_end = value; } - - // Override. - void clear(bool mangle_space); - - // Set both the 'hard' and 'soft' limits (_end and _soft_end). - void set_end(HeapWord* value) { - set_soft_end(value); - ContiguousSpace::set_end(value); - } - - // Allocation (return NULL if full) - HeapWord* allocate(size_t word_size); - HeapWord* par_allocate(size_t word_size); -}; - -// Class ConcEdenSpace extends EdenSpace for the sake of safe -// allocation while soft-end is being modified concurrently - -class ConcEdenSpace : public EdenSpace { - public: - ConcEdenSpace(DefNewGeneration* gen) : EdenSpace(gen) { } - - // Allocation (return NULL if full) - HeapWord* par_allocate(size_t word_size); -}; - - // A ContigSpace that Supports an efficient "block_start" operation via // a BlockOffsetArray (whose BlockOffsetSharedArray may be shared with // other spaces.) This is the abstract base class for old generation diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/memory/space.inline.hpp --- a/hotspot/src/share/vm/memory/space.inline.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/memory/space.inline.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -25,6 +25,9 @@ #ifndef SHARE_VM_MEMORY_SPACE_INLINE_HPP #define SHARE_VM_MEMORY_SPACE_INLINE_HPP +#include "gc_implementation/shared/liveRange.hpp" +#include "gc_implementation/shared/markSweep.inline.hpp" +#include "gc_implementation/shared/spaceDecorator.hpp" #include "gc_interface/collectedHeap.hpp" #include "memory/space.hpp" #include "memory/universe.hpp" @@ -35,272 +38,6 @@ return block_start_const(p); } -#define SCAN_AND_FORWARD(cp,scan_limit,block_is_obj,block_size) { \ - /* Compute the new addresses for the live objects and store it in the mark \ - * Used by universe::mark_sweep_phase2() \ - */ \ - HeapWord* compact_top; /* This is where we are currently compacting to. */ \ - \ - /* We're sure to be here before any objects are compacted into this \ - * space, so this is a good time to initialize this: \ - */ \ - set_compaction_top(bottom()); \ - \ - if (cp->space == NULL) { \ - assert(cp->gen != NULL, "need a generation"); \ - assert(cp->threshold == NULL, "just checking"); \ - assert(cp->gen->first_compaction_space() == this, "just checking"); \ - cp->space = cp->gen->first_compaction_space(); \ - compact_top = cp->space->bottom(); \ - cp->space->set_compaction_top(compact_top); \ - cp->threshold = cp->space->initialize_threshold(); \ - } else { \ - compact_top = cp->space->compaction_top(); \ - } \ - \ - /* We allow some amount of garbage towards the bottom of the space, so \ - * we don't start compacting before there is a significant gain to be made.\ - * Occasionally, we want to ensure a full compaction, which is determined \ - * by the MarkSweepAlwaysCompactCount parameter. \ - */ \ - uint invocations = MarkSweep::total_invocations(); \ - bool skip_dead = ((invocations % MarkSweepAlwaysCompactCount) != 0); \ - \ - size_t allowed_deadspace = 0; \ - if (skip_dead) { \ - const size_t ratio = allowed_dead_ratio(); \ - allowed_deadspace = (capacity() * ratio / 100) / HeapWordSize; \ - } \ - \ - HeapWord* q = bottom(); \ - HeapWord* t = scan_limit(); \ - \ - HeapWord* end_of_live= q; /* One byte beyond the last byte of the last \ - live object. */ \ - HeapWord* first_dead = end();/* The first dead object. */ \ - LiveRange* liveRange = NULL; /* The current live range, recorded in the \ - first header of preceding free area. */ \ - _first_dead = first_dead; \ - \ - const intx interval = PrefetchScanIntervalInBytes; \ - \ - while (q < t) { \ - assert(!block_is_obj(q) || \ - oop(q)->mark()->is_marked() || oop(q)->mark()->is_unlocked() || \ - oop(q)->mark()->has_bias_pattern(), \ - "these are the only valid states during a mark sweep"); \ - if (block_is_obj(q) && oop(q)->is_gc_marked()) { \ - /* prefetch beyond q */ \ - Prefetch::write(q, interval); \ - size_t size = block_size(q); \ - compact_top = cp->space->forward(oop(q), size, cp, compact_top); \ - q += size; \ - end_of_live = q; \ - } else { \ - /* run over all the contiguous dead objects */ \ - HeapWord* end = q; \ - do { \ - /* prefetch beyond end */ \ - Prefetch::write(end, interval); \ - end += block_size(end); \ - } while (end < t && (!block_is_obj(end) || !oop(end)->is_gc_marked()));\ - \ - /* see if we might want to pretend this object is alive so that \ - * we don't have to compact quite as often. \ - */ \ - if (allowed_deadspace > 0 && q == compact_top) { \ - size_t sz = pointer_delta(end, q); \ - if (insert_deadspace(allowed_deadspace, q, sz)) { \ - compact_top = cp->space->forward(oop(q), sz, cp, compact_top); \ - q = end; \ - end_of_live = end; \ - continue; \ - } \ - } \ - \ - /* otherwise, it really is a free region. */ \ - \ - /* for the previous LiveRange, record the end of the live objects. */ \ - if (liveRange) { \ - liveRange->set_end(q); \ - } \ - \ - /* record the current LiveRange object. \ - * liveRange->start() is overlaid on the mark word. \ - */ \ - liveRange = (LiveRange*)q; \ - liveRange->set_start(end); \ - liveRange->set_end(end); \ - \ - /* see if this is the first dead region. */ \ - if (q < first_dead) { \ - first_dead = q; \ - } \ - \ - /* move on to the next object */ \ - q = end; \ - } \ - } \ - \ - assert(q == t, "just checking"); \ - if (liveRange != NULL) { \ - liveRange->set_end(q); \ - } \ - _end_of_live = end_of_live; \ - if (end_of_live < first_dead) { \ - first_dead = end_of_live; \ - } \ - _first_dead = first_dead; \ - \ - /* save the compaction_top of the compaction space. */ \ - cp->space->set_compaction_top(compact_top); \ -} - -#define SCAN_AND_ADJUST_POINTERS(adjust_obj_size) { \ - /* adjust all the interior pointers to point at the new locations of objects \ - * Used by MarkSweep::mark_sweep_phase3() */ \ - \ - HeapWord* q = bottom(); \ - HeapWord* t = _end_of_live; /* Established by "prepare_for_compaction". */ \ - \ - assert(_first_dead <= _end_of_live, "Stands to reason, no?"); \ - \ - if (q < t && _first_dead > q && \ - !oop(q)->is_gc_marked()) { \ - /* we have a chunk of the space which hasn't moved and we've \ - * reinitialized the mark word during the previous pass, so we can't \ - * use is_gc_marked for the traversal. */ \ - HeapWord* end = _first_dead; \ - \ - while (q < end) { \ - /* I originally tried to conjoin "block_start(q) == q" to the \ - * assertion below, but that doesn't work, because you can't \ - * accurately traverse previous objects to get to the current one \ - * after their pointers have been \ - * updated, until the actual compaction is done. dld, 4/00 */ \ - assert(block_is_obj(q), \ - "should be at block boundaries, and should be looking at objs"); \ - \ - /* point all the oops to the new location */ \ - size_t size = oop(q)->adjust_pointers(); \ - size = adjust_obj_size(size); \ - \ - q += size; \ - } \ - \ - if (_first_dead == t) { \ - q = t; \ - } else { \ - /* $$$ This is funky. Using this to read the previously written \ - * LiveRange. See also use below. */ \ - q = (HeapWord*)oop(_first_dead)->mark()->decode_pointer(); \ - } \ - } \ - \ - const intx interval = PrefetchScanIntervalInBytes; \ - \ - debug_only(HeapWord* prev_q = NULL); \ - while (q < t) { \ - /* prefetch beyond q */ \ - Prefetch::write(q, interval); \ - if (oop(q)->is_gc_marked()) { \ - /* q is alive */ \ - /* point all the oops to the new location */ \ - size_t size = oop(q)->adjust_pointers(); \ - size = adjust_obj_size(size); \ - debug_only(prev_q = q); \ - q += size; \ - } else { \ - /* q is not a live object, so its mark should point at the next \ - * live object */ \ - debug_only(prev_q = q); \ - q = (HeapWord*) oop(q)->mark()->decode_pointer(); \ - assert(q > prev_q, "we should be moving forward through memory"); \ - } \ - } \ - \ - assert(q == t, "just checking"); \ -} - -#define SCAN_AND_COMPACT(obj_size) { \ - /* Copy all live objects to their new location \ - * Used by MarkSweep::mark_sweep_phase4() */ \ - \ - HeapWord* q = bottom(); \ - HeapWord* const t = _end_of_live; \ - debug_only(HeapWord* prev_q = NULL); \ - \ - if (q < t && _first_dead > q && \ - !oop(q)->is_gc_marked()) { \ - debug_only( \ - /* we have a chunk of the space which hasn't moved and we've reinitialized \ - * the mark word during the previous pass, so we can't use is_gc_marked for \ - * the traversal. */ \ - HeapWord* const end = _first_dead; \ - \ - while (q < end) { \ - size_t size = obj_size(q); \ - assert(!oop(q)->is_gc_marked(), \ - "should be unmarked (special dense prefix handling)"); \ - debug_only(prev_q = q); \ - q += size; \ - } \ - ) /* debug_only */ \ - \ - if (_first_dead == t) { \ - q = t; \ - } else { \ - /* $$$ Funky */ \ - q = (HeapWord*) oop(_first_dead)->mark()->decode_pointer(); \ - } \ - } \ - \ - const intx scan_interval = PrefetchScanIntervalInBytes; \ - const intx copy_interval = PrefetchCopyIntervalInBytes; \ - while (q < t) { \ - 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(); \ - assert(q > prev_q, "we should be moving forward through memory"); \ - } else { \ - /* prefetch beyond q */ \ - Prefetch::read(q, scan_interval); \ - \ - /* size and destination */ \ - size_t size = obj_size(q); \ - HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee(); \ - \ - /* prefetch beyond compaction_top */ \ - Prefetch::write(compaction_top, copy_interval); \ - \ - /* 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(); \ - assert(oop(compaction_top)->klass() != NULL, "should have a class"); \ - \ - debug_only(prev_q = q); \ - q += size; \ - } \ - } \ - \ - /* Let's remember if we were empty before we did the compaction. */ \ - bool was_empty = used_region().is_empty(); \ - /* Reset space after compaction is complete */ \ - reset_after_compaction(); \ - /* We do this clear, below, since it has overloaded meanings for some */ \ - /* space subtypes. For example, OffsetTableContigSpace's that were */ \ - /* compacted into will have had their offset table thresholds updated */ \ - /* continuously, but those that weren't need to have their thresholds */ \ - /* re-initialized. Also mangles unused area for debugging. */ \ - if (used_region().is_empty()) { \ - if (!was_empty) clear(SpaceDecorator::Mangle); \ - } else { \ - if (ZapUnusedHeapArea) mangle_unused_area(); \ - } \ -} - inline HeapWord* OffsetTableContigSpace::allocate(size_t size) { HeapWord* res = ContiguousSpace::allocate(size); if (res != NULL) { @@ -334,4 +71,263 @@ return _offsets.block_start(p); } +template +inline void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp) { + // Compute the new addresses for the live objects and store it in the mark + // Used by universe::mark_sweep_phase2() + HeapWord* compact_top; // This is where we are currently compacting to. + + // We're sure to be here before any objects are compacted into this + // space, so this is a good time to initialize this: + space->set_compaction_top(space->bottom()); + + if (cp->space == NULL) { + assert(cp->gen != NULL, "need a generation"); + assert(cp->threshold == NULL, "just checking"); + assert(cp->gen->first_compaction_space() == space, "just checking"); + cp->space = cp->gen->first_compaction_space(); + compact_top = cp->space->bottom(); + cp->space->set_compaction_top(compact_top); + cp->threshold = cp->space->initialize_threshold(); + } else { + compact_top = cp->space->compaction_top(); + } + + // We allow some amount of garbage towards the bottom of the space, so + // we don't start compacting before there is a significant gain to be made. + // Occasionally, we want to ensure a full compaction, which is determined + // by the MarkSweepAlwaysCompactCount parameter. + uint invocations = MarkSweep::total_invocations(); + bool skip_dead = ((invocations % MarkSweepAlwaysCompactCount) != 0); + + size_t allowed_deadspace = 0; + if (skip_dead) { + const size_t ratio = space->allowed_dead_ratio(); + allowed_deadspace = (space->capacity() * ratio / 100) / HeapWordSize; + } + + HeapWord* q = space->bottom(); + HeapWord* t = space->scan_limit(); + + HeapWord* end_of_live= q; // One byte beyond the last byte of the last + // live object. + HeapWord* first_dead = space->end(); // The first dead object. + LiveRange* liveRange = NULL; // The current live range, recorded in the + // first header of preceding free area. + space->_first_dead = first_dead; + + const intx interval = PrefetchScanIntervalInBytes; + + while (q < t) { + assert(!space->scanned_block_is_obj(q) || + oop(q)->mark()->is_marked() || oop(q)->mark()->is_unlocked() || + oop(q)->mark()->has_bias_pattern(), + "these are the only valid states during a mark sweep"); + if (space->scanned_block_is_obj(q) && oop(q)->is_gc_marked()) { + // prefetch beyond q + Prefetch::write(q, interval); + size_t size = space->scanned_block_size(q); + compact_top = cp->space->forward(oop(q), size, cp, compact_top); + q += size; + end_of_live = q; + } else { + // run over all the contiguous dead objects + HeapWord* end = q; + do { + // prefetch beyond end + Prefetch::write(end, interval); + end += space->scanned_block_size(end); + } while (end < t && (!space->scanned_block_is_obj(end) || !oop(end)->is_gc_marked())); + + // see if we might want to pretend this object is alive so that + // we don't have to compact quite as often. + if (allowed_deadspace > 0 && q == compact_top) { + size_t sz = pointer_delta(end, q); + if (space->insert_deadspace(allowed_deadspace, q, sz)) { + compact_top = cp->space->forward(oop(q), sz, cp, compact_top); + q = end; + end_of_live = end; + continue; + } + } + + // otherwise, it really is a free region. + + // for the previous LiveRange, record the end of the live objects. + if (liveRange) { + liveRange->set_end(q); + } + + // record the current LiveRange object. + // liveRange->start() is overlaid on the mark word. + liveRange = (LiveRange*)q; + liveRange->set_start(end); + liveRange->set_end(end); + + // see if this is the first dead region. + if (q < first_dead) { + first_dead = q; + } + + // move on to the next object + q = end; + } + } + + assert(q == t, "just checking"); + if (liveRange != NULL) { + liveRange->set_end(q); + } + space->_end_of_live = end_of_live; + if (end_of_live < first_dead) { + first_dead = end_of_live; + } + space->_first_dead = first_dead; + + // save the compaction_top of the compaction space. + cp->space->set_compaction_top(compact_top); +} + +template +inline void CompactibleSpace::scan_and_adjust_pointers(SpaceType* space) { + // adjust all the interior pointers to point at the new locations of objects + // Used by MarkSweep::mark_sweep_phase3() + + HeapWord* q = space->bottom(); + HeapWord* t = space->_end_of_live; // Established by "prepare_for_compaction". + + assert(space->_first_dead <= space->_end_of_live, "Stands to reason, no?"); + + if (q < t && space->_first_dead > q && !oop(q)->is_gc_marked()) { + // we have a chunk of the space which hasn't moved and we've + // reinitialized the mark word during the previous pass, so we can't + // use is_gc_marked for the traversal. + HeapWord* end = space->_first_dead; + + while (q < end) { + // I originally tried to conjoin "block_start(q) == q" to the + // assertion below, but that doesn't work, because you can't + // accurately traverse previous objects to get to the current one + // after their pointers have been + // updated, until the actual compaction is done. dld, 4/00 + assert(space->block_is_obj(q), "should be at block boundaries, and should be looking at objs"); + + // point all the oops to the new location + size_t size = oop(q)->adjust_pointers(); + size = space->adjust_obj_size(size); + + q += size; + } + + if (space->_first_dead == t) { + q = t; + } else { + // $$$ This is funky. Using this to read the previously written + // LiveRange. See also use below. + q = (HeapWord*)oop(space->_first_dead)->mark()->decode_pointer(); + } + } + + const intx interval = PrefetchScanIntervalInBytes; + + debug_only(HeapWord* prev_q = NULL); + while (q < t) { + // prefetch beyond q + Prefetch::write(q, interval); + if (oop(q)->is_gc_marked()) { + // q is alive + // point all the oops to the new location + size_t size = oop(q)->adjust_pointers(); + size = space->adjust_obj_size(size); + debug_only(prev_q = q); + q += size; + } else { + // q is not a live object, so its mark should point at the next + // live object + debug_only(prev_q = q); + q = (HeapWord*) oop(q)->mark()->decode_pointer(); + assert(q > prev_q, "we should be moving forward through memory"); + } + } + + assert(q == t, "just checking"); +} + +template +inline void CompactibleSpace::scan_and_compact(SpaceType* space) { + // Copy all live objects to their new location + // Used by MarkSweep::mark_sweep_phase4() + + HeapWord* q = space->bottom(); + HeapWord* const t = space->_end_of_live; + debug_only(HeapWord* prev_q = NULL); + + if (q < t && space->_first_dead > q && !oop(q)->is_gc_marked()) { + #ifdef ASSERT // Debug only + // we have a chunk of the space which hasn't moved and we've reinitialized + // the mark word during the previous pass, so we can't use is_gc_marked for + // the traversal. + HeapWord* const end = space->_first_dead; + + while (q < end) { + size_t size = space->obj_size(q); + assert(!oop(q)->is_gc_marked(), "should be unmarked (special dense prefix handling)"); + prev_q = q; + q += size; + } + #endif + + if (space->_first_dead == t) { + q = t; + } else { + // $$$ Funky + q = (HeapWord*) oop(space->_first_dead)->mark()->decode_pointer(); + } + } + + const intx scan_interval = PrefetchScanIntervalInBytes; + const intx copy_interval = PrefetchCopyIntervalInBytes; + while (q < t) { + 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(); + assert(q > prev_q, "we should be moving forward through memory"); + } else { + // prefetch beyond q + Prefetch::read(q, scan_interval); + + // size and destination + size_t size = space->obj_size(q); + HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee(); + + // prefetch beyond compaction_top + Prefetch::write(compaction_top, copy_interval); + + // 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(); + assert(oop(compaction_top)->klass() != NULL, "should have a class"); + + debug_only(prev_q = q); + q += size; + } + } + + // Let's remember if we were empty before we did the compaction. + bool was_empty = space->used_region().is_empty(); + // Reset space after compaction is complete + space->reset_after_compaction(); + // We do this clear, below, since it has overloaded meanings for some + // space subtypes. For example, OffsetTableContigSpace's that were + // compacted into will have had their offset table thresholds updated + // continuously, but those that weren't need to have their thresholds + // re-initialized. Also mangles unused area for debugging. + if (space->used_region().is_empty()) { + if (!was_empty) space->clear(SpaceDecorator::Mangle); + } else { + if (ZapUnusedHeapArea) space->mangle_unused_area(); + } +} #endif // SHARE_VM_MEMORY_SPACE_INLINE_HPP diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/oops/constMethod.cpp --- a/hotspot/src/share/vm/oops/constMethod.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/oops/constMethod.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -116,7 +116,11 @@ if (sizes->generic_signature_index() != 0) { extra_bytes += sizeof(u2); } - if (sizes->method_parameters_length() > 0) { + // This has to be a less-than-or-equal check, because we might be + // storing information from a zero-length MethodParameters + // attribute. We have to store these, because in some cases, they + // cause the reflection API to throw a MalformedParametersException. + if (sizes->method_parameters_length() >= 0) { extra_bytes += sizeof(u2); extra_bytes += sizes->method_parameters_length() * sizeof(MethodParametersElement); } @@ -237,7 +241,7 @@ _flags |= _has_linenumber_table; if (sizes->generic_signature_index() != 0) _flags |= _has_generic_signature; - if (sizes->method_parameters_length() > 0) + if (sizes->method_parameters_length() >= 0) _flags |= _has_method_parameters; if (sizes->checked_exceptions_length() > 0) _flags |= _has_checked_exceptions; @@ -272,7 +276,7 @@ if (sizes->generic_signature_index() != 0) *(generic_signature_index_addr()) = sizes->generic_signature_index(); // New data should probably go here. - if (sizes->method_parameters_length() > 0) + if (sizes->method_parameters_length() >= 0) *(method_parameters_length_addr()) = sizes->method_parameters_length(); if (sizes->checked_exceptions_length() > 0) *(checked_exceptions_length_addr()) = sizes->checked_exceptions_length(); @@ -283,7 +287,7 @@ } int ConstMethod::method_parameters_length() const { - return has_method_parameters() ? *(method_parameters_length_addr()) : 0; + return has_method_parameters() ? *(method_parameters_length_addr()) : -1; } MethodParametersElement* ConstMethod::method_parameters_start() const { diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/oops/constMethod.hpp --- a/hotspot/src/share/vm/oops/constMethod.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/oops/constMethod.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -372,6 +372,11 @@ ExceptionTableElement* exception_table_start() const; // method parameters table + + // This returns -1 if no parameters are present, a non-negative + // value otherwise. Note: sometimes, there are 0-length parameters + // attributes that must be reported up to the reflection API all the + // same. int method_parameters_length() const; MethodParametersElement* method_parameters_start() const; diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/oops/method.cpp --- a/hotspot/src/share/vm/oops/method.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/oops/method.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -588,6 +588,15 @@ return true; } +bool Method::is_constant_getter() const { + int last_index = code_size() - 1; + // Check if the first 1-3 bytecodes are a constant push + // and the last bytecode is a return. + return (2 <= code_size() && code_size() <= 4 && + Bytecodes::is_const(java_code_at(0)) && + Bytecodes::length_for(java_code_at(0)) == last_index && + Bytecodes::is_return(java_code_at(last_index))); +} bool Method::is_initializer() const { return name() == vmSymbols::object_initializer_name() || is_static_initializer(); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/oops/method.hpp --- a/hotspot/src/share/vm/oops/method.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/oops/method.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -595,6 +595,9 @@ // returns true if the method is an accessor function (setter/getter). bool is_accessor() const; + // returns true if the method does nothing but return a constant of primitive type + bool is_constant_getter() const; + // returns true if the method is an initializer ( or ). bool is_initializer() const; diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/oops/methodData.cpp --- a/hotspot/src/share/vm/oops/methodData.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/oops/methodData.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -1134,7 +1134,7 @@ _tenure_traps = 0; _num_loops = 0; _num_blocks = 0; - _would_profile = true; + _would_profile = unknown; #if INCLUDE_RTM_OPT _rtm_state = NoRTM; // No RTM lock eliding by default diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/oops/methodData.hpp --- a/hotspot/src/share/vm/oops/methodData.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/oops/methodData.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -2096,7 +2096,8 @@ short _num_loops; short _num_blocks; // Does this method contain anything worth profiling? - bool _would_profile; + enum WouldProfile {unknown, no_profile, profile}; + WouldProfile _would_profile; // Size of _data array in bytes. (Excludes header and extra_data fields.) int _data_size; @@ -2270,8 +2271,8 @@ } #endif - void set_would_profile(bool p) { _would_profile = p; } - bool would_profile() const { return _would_profile; } + void set_would_profile(bool p) { _would_profile = p ? profile : no_profile; } + bool would_profile() const { return _would_profile != no_profile; } int num_loops() const { return _num_loops; } void set_num_loops(int n) { _num_loops = n; } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/opto/doCall.cpp --- a/hotspot/src/share/vm/opto/doCall.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/opto/doCall.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -794,7 +794,7 @@ Node* ex_klass_node = NULL; if (has_ex_handler() && !ex_type->klass_is_exact()) { Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes()); - ex_klass_node = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) ); + ex_klass_node = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT)); // Compute the exception klass a little more cleverly. // Obvious solution is to simple do a LoadKlass from the 'ex_node'. @@ -812,7 +812,7 @@ continue; } Node* p = basic_plus_adr(ex_in, ex_in, oopDesc::klass_offset_in_bytes()); - Node* k = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) ); + Node* k = _gvn.transform( LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT)); ex_klass_node->init_req( i, k ); } _gvn.set_type(ex_klass_node, TypeKlassPtr::OBJECT); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/opto/graphKit.cpp --- a/hotspot/src/share/vm/opto/graphKit.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/opto/graphKit.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -1154,7 +1154,7 @@ Node* akls = AllocateNode::Ideal_klass(obj, &_gvn); if (akls != NULL) return akls; Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); - return _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS) ); + return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS)); } //-------------------------load_array_length----------------------------------- @@ -2615,7 +2615,7 @@ // types load from the super-class display table which is immutable. m = mem->memory_at(C->get_alias_index(gvn->type(p2)->is_ptr())); Node *kmem = might_be_cache ? m : C->immutable_memory(); - Node *nkls = gvn->transform(LoadKlassNode::make(*gvn, kmem, p2, gvn->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL)); + Node *nkls = gvn->transform(LoadKlassNode::make(*gvn, NULL, kmem, p2, gvn->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL)); // Compile speed common case: ARE a subtype and we canNOT fail if( superklass == nkls ) diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/opto/library_call.cpp --- a/hotspot/src/share/vm/opto/library_call.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/opto/library_call.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -3345,7 +3345,7 @@ if (region == NULL) never_see_null = true; Node* p = basic_plus_adr(mirror, offset); const TypeKlassPtr* kls_type = TypeKlassPtr::OBJECT_OR_NULL; - Node* kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type)); + Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type)); Node* null_ctl = top(); kls = null_check_oop(kls, &null_ctl, never_see_null); if (region != NULL) { @@ -3517,7 +3517,7 @@ phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror()))); // If we fall through, it's a plain class. Get its _super. p = basic_plus_adr(kls, in_bytes(Klass::super_offset())); - kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL)); + kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL)); null_ctl = top(); kls = null_check_oop(kls, &null_ctl); if (null_ctl != top()) { @@ -3671,7 +3671,7 @@ args[which_arg] = arg; Node* p = basic_plus_adr(arg, class_klass_offset); - Node* kls = LoadKlassNode::make(_gvn, immutable_memory(), p, adr_type, kls_type); + Node* kls = LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, adr_type, kls_type); klasses[which_arg] = _gvn.transform(kls); } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/opto/macro.cpp --- a/hotspot/src/share/vm/opto/macro.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/opto/macro.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -1197,8 +1197,7 @@ } if (C->env()->dtrace_alloc_probes() || - !UseTLAB && (!Universe::heap()->supports_inline_contig_alloc() || - (UseConcMarkSweepGC && CMSIncrementalMode))) { + !UseTLAB && (!Universe::heap()->supports_inline_contig_alloc())) { // Force slow-path allocation always_slow = true; initial_slow_test = NULL; @@ -2202,7 +2201,7 @@ Node* klass_node = AllocateNode::Ideal_klass(obj, &_igvn); if (klass_node == NULL) { Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes()); - klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) ); + klass_node = transform_later(LoadKlassNode::make(_igvn, NULL, mem, k_adr, _igvn.type(k_adr)->is_ptr())); #ifdef _LP64 if (UseCompressedClassPointers && klass_node->is_DecodeNKlass()) { assert(klass_node->in(1)->Opcode() == Op_LoadNKlass, "sanity"); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/opto/macroArrayCopy.cpp --- a/hotspot/src/share/vm/opto/macroArrayCopy.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/opto/macroArrayCopy.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -529,7 +529,7 @@ // (At this point we can assume disjoint_bases, since types differ.) int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node* p1 = basic_plus_adr(dest_klass, ek_offset); - Node* n1 = LoadKlassNode::make(_igvn, C->immutable_memory(), p1, TypeRawPtr::BOTTOM); + Node* n1 = LoadKlassNode::make(_igvn, NULL, C->immutable_memory(), p1, TypeRawPtr::BOTTOM); Node* dest_elem_klass = transform_later(n1); Node* cv = generate_checkcast_arraycopy(&local_ctrl, &local_mem, adr_type, diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/opto/memnode.cpp --- a/hotspot/src/share/vm/opto/memnode.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/opto/memnode.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -861,6 +861,10 @@ //============================================================================= +// Should LoadNode::Ideal() attempt to remove control edges? +bool LoadNode::can_remove_control() const { + return true; +} uint LoadNode::size_of() const { return sizeof(*this); } uint LoadNode::cmp( const Node &n ) const { return !Type::cmp( _type, ((LoadNode&)n)._type ); } @@ -1471,7 +1475,7 @@ } //------------------------------Ideal------------------------------------------ -// If the load is from Field memory and the pointer is non-null, we can +// If the load is from Field memory and the pointer is non-null, it might be possible to // zero out the control input. // If the offset is constant and the base is an object allocation, // try to hook me up to the exact initializing store. @@ -1498,6 +1502,7 @@ && phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw) { // Check for useless control edge in some common special cases if (in(MemNode::Control) != NULL + && can_remove_control() && phase->type(base)->higher_equal(TypePtr::NOTNULL) && all_controls_dominate(base, phase->C->start())) { // A method-invariant, non-null address (constant or 'this' argument). @@ -2019,8 +2024,7 @@ //============================================================================= //----------------------------LoadKlassNode::make------------------------------ // Polymorphic factory method: -Node *LoadKlassNode::make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk ) { - Node *ctl = NULL; +Node* LoadKlassNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk) { // sanity check the alias category against the created node type const TypePtr *adr_type = adr->bottom_type()->isa_ptr(); assert(adr_type != NULL, "expecting TypeKlassPtr"); @@ -2040,6 +2044,12 @@ return klass_value_common(phase); } +// In most cases, LoadKlassNode does not have the control input set. If the control +// input is set, it must not be removed (by LoadNode::Ideal()). +bool LoadKlassNode::can_remove_control() const { + return false; +} + const Type *LoadNode::klass_value_common( PhaseTransform *phase ) const { // Either input is TOP ==> the result is TOP const Type *t1 = phase->type( in(MemNode::Memory) ); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/opto/memnode.hpp --- a/hotspot/src/share/vm/opto/memnode.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/opto/memnode.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -148,6 +148,8 @@ protected: virtual uint cmp(const Node &n) const; virtual uint size_of() const; // Size is bigger + // Should LoadNode::Ideal() attempt to remove control edges? + virtual bool can_remove_control() const; const Type* const _type; // What kind of value is loaded? public: @@ -171,8 +173,10 @@ // we are equivalent to. We look for Load of a Store. virtual Node *Identity( PhaseTransform *phase ); - // If the load is from Field memory and the pointer is non-null, we can + // If the load is from Field memory and the pointer is non-null, it might be possible to // zero out the control input. + // If the offset is constant and the base is an object allocation, + // try to hook me up to the exact initializing store. virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); // Split instance field load through Phi. @@ -431,6 +435,10 @@ //------------------------------LoadKlassNode---------------------------------- // Load a Klass from an object class LoadKlassNode : public LoadPNode { +protected: + // In most cases, LoadKlassNode does not have the control input set. If the control + // input is set, it must not be removed (by LoadNode::Ideal()). + virtual bool can_remove_control() const; public: LoadKlassNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk, MemOrd mo) : LoadPNode(c, mem, adr, at, tk, mo) {} @@ -440,8 +448,8 @@ virtual bool depends_only_on_test() const { return true; } // Polymorphic factory method: - static Node* make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, - const TypeKlassPtr *tk = TypeKlassPtr::OBJECT ); + static Node* make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at, + const TypeKlassPtr* tk = TypeKlassPtr::OBJECT); }; //------------------------------LoadNKlassNode--------------------------------- diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/opto/parse1.cpp --- a/hotspot/src/share/vm/opto/parse1.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/opto/parse1.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -1987,7 +1987,7 @@ // finalization. In general this will fold up since the concrete // class is often visible so the access flags are constant. Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() ); - Node* klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), klass_addr, TypeInstPtr::KLASS) ); + Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), klass_addr, TypeInstPtr::KLASS)); Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::access_flags_offset())); Node* access_flags = make_load(NULL, access_flags_addr, TypeInt::INT, T_INT, MemNode::unordered); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/opto/parseHelper.cpp --- a/hotspot/src/share/vm/opto/parseHelper.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/opto/parseHelper.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -156,22 +156,43 @@ int klass_offset = oopDesc::klass_offset_in_bytes(); Node* p = basic_plus_adr( ary, ary, klass_offset ); // p's type is array-of-OOPS plus klass_offset - Node* array_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS) ); + Node* array_klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS)); // Get the array klass const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr(); - // array_klass's type is generally INexact array-of-oop. Heroically - // cast the array klass to EXACT array and uncommon-trap if the cast - // fails. + // The type of array_klass is usually INexact array-of-oop. Heroically + // cast array_klass to EXACT array and uncommon-trap if the cast fails. + // Make constant out of the inexact array klass, but use it only if the cast + // succeeds. bool always_see_exact_class = false; if (MonomorphicArrayCheck - && !too_many_traps(Deoptimization::Reason_array_check)) { + && !too_many_traps(Deoptimization::Reason_array_check) + && !tak->klass_is_exact() + && tak != TypeKlassPtr::OBJECT) { + // Regarding the fourth condition in the if-statement from above: + // + // If the compiler has determined that the type of array 'ary' (represented + // by 'array_klass') is java/lang/Object, the compiler must not assume that + // the array 'ary' is monomorphic. + // + // If 'ary' were of type java/lang/Object, this arraystore would have to fail, + // because it is not possible to perform a arraystore into an object that is not + // a "proper" array. + // + // Therefore, let's obtain at runtime the type of 'ary' and check if we can still + // successfully perform the store. + // + // The implementation reasons for the condition are the following: + // + // java/lang/Object is the superclass of all arrays, but it is represented by the VM + // as an InstanceKlass. The checks generated by gen_checkcast() (see below) expect + // 'array_klass' to be ObjArrayKlass, which can result in invalid memory accesses. + // + // See issue JDK-8057622 for details. + always_see_exact_class = true; // (If no MDO at all, hope for the best, until a trap actually occurs.) - } - // Is the array klass is exactly its defined type? - if (always_see_exact_class && !tak->klass_is_exact()) { // Make a constant out of the inexact array klass const TypeKlassPtr *extak = tak->cast_to_exactness(true)->is_klassptr(); Node* con = makecon(extak); @@ -202,11 +223,15 @@ // Extract the array element class int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset()); Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset); - Node *a_e_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p2, tak) ); + // We are allowed to use the constant type only if cast succeeded. If always_see_exact_class is true, + // we must set a control edge from the IfTrue node created by the uncommon_trap above to the + // LoadKlassNode. + Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, always_see_exact_class ? control() : NULL, + immutable_memory(), p2, tak)); // Check (the hard way) and throw if not a subklass. // Result is ignored, we just need the CFG effects. - gen_checkcast( obj, a_e_klass ); + gen_checkcast(obj, a_e_klass); } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/prims/jvm.cpp --- a/hotspot/src/share/vm/prims/jvm.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/prims/jvm.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -1657,7 +1657,17 @@ Handle reflected_method (THREAD, JNIHandles::resolve_non_null(method)); const int num_params = mh->method_parameters_length(); - if (0 != num_params) { + if (num_params < 0) { + // A -1 return value from method_parameters_length means there is no + // parameter data. Return null to indicate this to the reflection + // API. + assert(num_params == -1, "num_params should be -1 if it is less than zero"); + return (jobjectArray)NULL; + } else { + // Otherwise, we return something up to reflection, even if it is + // a zero-length array. Why? Because in some cases this can + // trigger a MalformedParametersException. + // make sure all the symbols are properly formatted for (int i = 0; i < num_params; i++) { MethodParametersElement* params = mh->method_parameters_start(); @@ -1685,8 +1695,6 @@ result->obj_at_put(i, param); } return (jobjectArray)JNIHandles::make_local(env, result()); - } else { - return (jobjectArray)NULL; } } JVM_END diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/prims/whitebox.cpp --- a/hotspot/src/share/vm/prims/whitebox.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/prims/whitebox.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -24,6 +24,8 @@ #include "precompiled.hpp" +#include + #include "code/codeCache.hpp" #include "memory/metadataFactory.hpp" #include "memory/universe.hpp" @@ -37,9 +39,11 @@ #include "runtime/thread.hpp" #include "runtime/arguments.hpp" +#include "runtime/deoptimization.hpp" #include "runtime/interfaceSupport.hpp" #include "runtime/os.hpp" #include "runtime/vm_version.hpp" +#include "runtime/sweeper.hpp" #include "utilities/array.hpp" #include "utilities/debug.hpp" @@ -67,6 +71,7 @@ #define SIZE_T_MAX_VALUE ((size_t) -1) bool WhiteBox::_used = false; +volatile bool WhiteBox::compilation_locked = false; WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj)) return (jlong)(void*)JNIHandles::resolve(obj); @@ -302,13 +307,12 @@ WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size)) jlong addr = 0; - addr = (jlong)(uintptr_t)os::reserve_memory(size); - MemTracker::record_virtual_memory_type((address)addr, mtTest); + addr = (jlong)(uintptr_t)os::reserve_memory(size); + MemTracker::record_virtual_memory_type((address)addr, mtTest); return addr; WB_END - WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size)) os::commit_memory((char *)(uintptr_t)addr, size, !ExecMem); MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest); @@ -728,6 +732,29 @@ WB_END +WB_ENTRY(void, WB_LockCompilation(JNIEnv* env, jobject o, jlong timeout)) + WhiteBox::compilation_locked = true; +WB_END + +WB_ENTRY(void, WB_UnlockCompilation(JNIEnv* env, jobject o)) + MonitorLockerEx mo(Compilation_lock, Mutex::_no_safepoint_check_flag); + WhiteBox::compilation_locked = false; + mo.notify_all(); +WB_END + +void WhiteBox::force_sweep() { + guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled"); + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + NMethodSweeper::_should_sweep = true; + } + NMethodSweeper::possibly_sweep(); +} + +WB_ENTRY(void, WB_ForceNMethodSweep(JNIEnv* env, jobject o)) + WhiteBox::force_sweep(); +WB_END + WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString)) ResourceMark rm(THREAD); int len; @@ -774,6 +801,46 @@ return features_string; WB_END +int WhiteBox::get_blob_type(const CodeBlob* code) { + guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled"); + return CodeCache::get_code_heap(code)->code_blob_type(); +} + +CodeHeap* WhiteBox::get_code_heap(int blob_type) { + guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled"); + return CodeCache::get_code_heap(blob_type); +} + +struct CodeBlobStub { + CodeBlobStub(const CodeBlob* blob) : + name(os::strdup(blob->name())), + size(blob->size()), + blob_type(WhiteBox::get_blob_type(blob)) { } + ~CodeBlobStub() { os::free((void*) name); } + const char* const name; + const int size; + const int blob_type; +}; + +static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBlobStub* cb) { + jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); + CHECK_JNI_EXCEPTION_(env, NULL); + jobjectArray result = env->NewObjectArray(3, clazz, NULL); + + jstring name = env->NewStringUTF(cb->name); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetObjectArrayElement(result, 0, name); + + jobject obj = integerBox(thread, env, cb->size); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetObjectArrayElement(result, 1, obj); + + obj = integerBox(thread, env, cb->blob_type); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetObjectArrayElement(result, 2, obj); + + return result; +} WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr)) ResourceMark rm(THREAD); @@ -790,24 +857,90 @@ ThreadToNativeFromVM ttn(thread); jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); CHECK_JNI_EXCEPTION_(env, NULL); - result = env->NewObjectArray(3, clazz, NULL); + result = env->NewObjectArray(4, clazz, NULL); if (result == NULL) { return result; } + CodeBlobStub stub(code); + jobjectArray codeBlob = codeBlob2objectArray(thread, env, &stub); + env->SetObjectArrayElement(result, 0, codeBlob); + jobject level = integerBox(thread, env, code->comp_level()); CHECK_JNI_EXCEPTION_(env, NULL); - env->SetObjectArrayElement(result, 0, level); + env->SetObjectArrayElement(result, 1, level); jbyteArray insts = env->NewByteArray(insts_size); CHECK_JNI_EXCEPTION_(env, NULL); env->SetByteArrayRegion(insts, 0, insts_size, (jbyte*) code->insts_begin()); - env->SetObjectArrayElement(result, 1, insts); + env->SetObjectArrayElement(result, 2, insts); jobject id = integerBox(thread, env, code->compile_id()); CHECK_JNI_EXCEPTION_(env, NULL); - env->SetObjectArrayElement(result, 2, id); + env->SetObjectArrayElement(result, 3, id); + + return result; +WB_END + +CodeBlob* WhiteBox::allocate_code_blob(int size, int blob_type) { + guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled"); + BufferBlob* blob; + int full_size = CodeBlob::align_code_offset(sizeof(BufferBlob)); + if (full_size < size) { + full_size += round_to(size - full_size, oopSize); + } + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + blob = (BufferBlob*) CodeCache::allocate(full_size, blob_type); + } + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); + ::new (blob) BufferBlob("WB::DummyBlob", full_size); + return blob; +} + +WB_ENTRY(jlong, WB_AllocateCodeBlob(JNIEnv* env, jobject o, jint size, jint blob_type)) + return (jlong) WhiteBox::allocate_code_blob(size, blob_type); +WB_END + +WB_ENTRY(void, WB_FreeCodeBlob(JNIEnv* env, jobject o, jlong addr)) + BufferBlob::free((BufferBlob*) addr); +WB_END +WB_ENTRY(jobjectArray, WB_GetCodeHeapEntries(JNIEnv* env, jobject o, jint blob_type)) + ResourceMark rm; + GrowableArray blobs; + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + CodeHeap* heap = WhiteBox::get_code_heap(blob_type); + if (heap == NULL) { + return NULL; + } + for (CodeBlob* cb = (CodeBlob*) heap->first(); + cb != NULL; cb = (CodeBlob*) heap->next(cb)) { + CodeBlobStub* stub = NEW_RESOURCE_OBJ(CodeBlobStub); + new (stub) CodeBlobStub(cb); + blobs.append(stub); + } + } + if (blobs.length() == 0) { + return NULL; + } + ThreadToNativeFromVM ttn(thread); + jobjectArray result = NULL; + jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); + CHECK_JNI_EXCEPTION_(env, NULL); + result = env->NewObjectArray(blobs.length(), clazz, NULL); + if (result == NULL) { + return result; + } + int i = 0; + for (GrowableArrayIterator it = blobs.begin(); + it != blobs.end(); ++it) { + jobjectArray obj = codeBlob2objectArray(thread, env, *it); + env->SetObjectArrayElement(result, i, obj); + ++i; + } return result; WB_END @@ -1018,6 +1151,8 @@ CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation}, {CC"clearMethodState", CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState}, + {CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation}, + {CC"unlockCompilation", CC"()V", (void*)&WB_UnlockCompilation}, {CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag}, {CC"isLockedVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag}, {CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag}, @@ -1055,6 +1190,10 @@ {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, + {CC"forceNMethodSweep", CC"()V", (void*)&WB_ForceNMethodSweep }, + {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, + {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, + {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, {CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize }, {CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize }, }; diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/prims/whitebox.hpp --- a/hotspot/src/share/vm/prims/whitebox.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/prims/whitebox.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -54,17 +54,24 @@ } \ } while (0) +class CodeBlob; +class CodeHeap; + class WhiteBox : public AllStatic { private: static bool _used; public: + static volatile bool compilation_locked; static bool used() { return _used; } static void set_used() { _used = true; } static int offset_for_field(const char* field_name, oop object, Symbol* signature_symbol); static const char* lookup_jstring(const char* field_name, oop object); static bool lookup_bool(const char* field_name, oop object); - + static void force_sweep(); + static int get_blob_type(const CodeBlob* code); + static CodeHeap* get_code_heap(int blob_type); + static CodeBlob* allocate_code_blob(int blob_type, int size); static int array_bytes_to_length(size_t bytes); static void register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread, JNINativeMethod* method_array, int method_count); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp --- a/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/runtime/advancedThresholdPolicy.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -317,8 +317,8 @@ * c. 0 -> (3->2) -> 4. * In this case we enqueue a method for compilation at level 3, but the C1 queue is long enough * to enable the profiling to fully occur at level 0. In this case we change the compilation level - * of the method to 2, because it'll allow it to run much faster without full profiling while c2 - * is compiling. + * of the method to 2 while the request is still in-queue, because it'll allow it to run much faster + * without full profiling while c2 is compiling. * * d. 0 -> 3 -> 1 or 0 -> 2 -> 1. * After a method was once compiled with C1 it can be identified as trivial and be compiled to diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/runtime/arguments.cpp --- a/hotspot/src/share/vm/runtime/arguments.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -1777,7 +1777,7 @@ #ifdef ASSERT static bool verify_serial_gc_flags() { return (UseSerialGC && - !(UseParNewGC || (UseConcMarkSweepGC || CMSIncrementalMode) || UseG1GC || + !(UseParNewGC || (UseConcMarkSweepGC) || UseG1GC || UseParallelGC || UseParallelOldGC)); } #endif // ASSERT @@ -2191,10 +2191,6 @@ warning("Using the ParNew young collector with the Serial old collector is deprecated " "and will likely be removed in a future release"); } - - if (CMSIncrementalMode) { - warning("Using incremental CMS is deprecated and will likely be removed in a future release"); - } } void Arguments::check_deprecated_gc_flags() { @@ -2316,31 +2312,8 @@ status = status && ArgumentsExt::check_gc_consistency_user(); status = status && check_stack_pages(); - if (CMSIncrementalMode) { - if (!UseConcMarkSweepGC) { - jio_fprintf(defaultStream::error_stream(), - "error: invalid argument combination.\n" - "The CMS collector (-XX:+UseConcMarkSweepGC) must be " - "selected in order\nto use CMSIncrementalMode.\n"); - status = false; - } else { - status = status && verify_percentage(CMSIncrementalDutyCycle, - "CMSIncrementalDutyCycle"); - status = status && verify_percentage(CMSIncrementalDutyCycleMin, - "CMSIncrementalDutyCycleMin"); - status = status && verify_percentage(CMSIncrementalSafetyFactor, - "CMSIncrementalSafetyFactor"); - status = status && verify_percentage(CMSIncrementalOffset, - "CMSIncrementalOffset"); - status = status && verify_percentage(CMSExpAvgFactor, - "CMSExpAvgFactor"); - // If it was not set on the command line, set - // CMSInitiatingOccupancyFraction to 1 so icms can initiate cycles early. - if (CMSInitiatingOccupancyFraction < 0) { - FLAG_SET_DEFAULT(CMSInitiatingOccupancyFraction, 1); - } - } - } + status = status && verify_percentage(CMSIncrementalSafetyFactor, + "CMSIncrementalSafetyFactor"); // CMS space iteration, which FLSVerifyAllHeapreferences entails, // insists that we hold the requisite locks so that the iteration is @@ -2874,14 +2847,6 @@ // -Xnoclassgc } else if (match_option(option, "-Xnoclassgc", &tail)) { FLAG_SET_CMDLINE(bool, ClassUnloading, false); - // -Xincgc: i-CMS - } else if (match_option(option, "-Xincgc", &tail)) { - FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true); - FLAG_SET_CMDLINE(bool, CMSIncrementalMode, true); - // -Xnoincgc: no i-CMS - } else if (match_option(option, "-Xnoincgc", &tail)) { - FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false); - FLAG_SET_CMDLINE(bool, CMSIncrementalMode, false); // -Xconcgc } else if (match_option(option, "-Xconcgc", &tail)) { FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true); @@ -3711,7 +3676,6 @@ #if !INCLUDE_ALL_GCS static void force_serial_gc() { FLAG_SET_DEFAULT(UseSerialGC, true); - FLAG_SET_DEFAULT(CMSIncrementalMode, false); // special CMS suboption UNSUPPORTED_GC_OPTION(UseG1GC); UNSUPPORTED_GC_OPTION(UseParallelGC); UNSUPPORTED_GC_OPTION(UseParallelOldGC); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/runtime/globals.hpp --- a/hotspot/src/share/vm/runtime/globals.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/runtime/globals.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -1638,30 +1638,10 @@ "The maximum size of young gen chosen by default per GC worker " \ "thread available") \ \ - product(bool, CMSIncrementalMode, false, \ - "Whether CMS GC should operate in \"incremental\" mode") \ - \ - product(uintx, CMSIncrementalDutyCycle, 10, \ - "Percentage (0-100) of CMS incremental mode duty cycle. If " \ - "CMSIncrementalPacing is enabled, then this is just the initial " \ - "value.") \ - \ - product(bool, CMSIncrementalPacing, true, \ - "Whether the CMS incremental mode duty cycle should be " \ - "automatically adjusted") \ - \ - product(uintx, CMSIncrementalDutyCycleMin, 0, \ - "Minimum percentage (0-100) of the CMS incremental duty cycle " \ - "used when CMSIncrementalPacing is enabled") \ - \ product(uintx, CMSIncrementalSafetyFactor, 10, \ "Percentage (0-100) used to add conservatism when computing the " \ "duty cycle") \ \ - product(uintx, CMSIncrementalOffset, 0, \ - "Percentage (0-100) by which the CMS incremental mode duty cycle "\ - "is shifted to the right within the period between young GCs") \ - \ product(uintx, CMSExpAvgFactor, 50, \ "Percentage (0-100) used to weight the current sample when " \ "computing exponential averages for CMS statistics") \ @@ -1720,15 +1700,6 @@ "Skip block flux-rate sampling for an epoch unless inter-sweep " \ "duration exceeds this threshold in milliseconds") \ \ - develop(bool, CMSTraceIncrementalMode, false, \ - "Trace CMS incremental mode") \ - \ - develop(bool, CMSTraceIncrementalPacing, false, \ - "Trace CMS incremental mode pacing computation") \ - \ - develop(bool, CMSTraceThreadState, false, \ - "Trace the CMS thread state (enable the trace_state() method)") \ - \ product(bool, CMSClassUnloadingEnabled, true, \ "Whether class unloading enabled when using CMS GC") \ \ diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/runtime/mutexLocker.cpp --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -72,7 +72,6 @@ Monitor* CGC_lock = NULL; Monitor* STS_lock = NULL; Monitor* SLT_lock = NULL; -Monitor* iCMS_lock = NULL; Monitor* FullGCCount_lock = NULL; Monitor* CMark_lock = NULL; Mutex* CMRegionStack_lock = NULL; @@ -88,6 +87,7 @@ Mutex* Compile_lock = NULL; Monitor* MethodCompileQueue_lock = NULL; Monitor* CompileThread_lock = NULL; +Monitor* Compilation_lock = NULL; Mutex* CompileTaskAlloc_lock = NULL; Mutex* CompileStatistics_lock = NULL; Mutex* MultiArray_lock = NULL; @@ -175,9 +175,6 @@ def(CGC_lock , Monitor, special, true ); // coordinate between fore- and background GC def(STS_lock , Monitor, leaf, true ); - if (UseConcMarkSweepGC) { - def(iCMS_lock , Monitor, special, true ); // CMS incremental mode start/stop notification - } if (UseConcMarkSweepGC || UseG1GC) { def(FullGCCount_lock , Monitor, leaf, true ); // in support of ExplicitGCInvokesConcurrent } @@ -278,7 +275,9 @@ def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread def(CompileThread_lock , Monitor, nonleaf+5, false ); def(PeriodicTask_lock , Monitor, nonleaf+5, true); - + if (WhiteBoxAPI) { + def(Compilation_lock , Monitor, leaf, false ); + } #ifdef INCLUDE_TRACE def(JfrMsg_lock , Monitor, leaf, true); def(JfrBuffer_lock , Mutex, leaf, true); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/runtime/mutexLocker.hpp --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -66,7 +66,6 @@ // fore- & background GC threads. extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet. extern Monitor* SLT_lock; // used in CMS GC for acquiring PLL -extern Monitor* iCMS_lock; // CMS incremental mode start/stop notification extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc extern Monitor* CMark_lock; // used for concurrent mark thread coordination extern Mutex* CMRegionStack_lock; // used for protecting accesses to the CM region stack @@ -91,6 +90,7 @@ extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc) extern Monitor* MethodCompileQueue_lock; // a lock held when method compilations are enqueued, dequeued extern Monitor* CompileThread_lock; // a lock held by compile threads during compilation system initialization +extern Monitor* Compilation_lock; // a lock used to pause compilation extern Mutex* CompileTaskAlloc_lock; // a lock held when CompileTasks are allocated extern Mutex* CompileStatistics_lock; // a lock held when updating compilation statistics extern Mutex* MultiArray_lock; // a lock used to guard allocation of multi-dim arrays diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/runtime/objectMonitor.hpp --- a/hotspot/src/share/vm/runtime/objectMonitor.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/runtime/objectMonitor.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -228,6 +228,20 @@ static int Responsible_offset_in_bytes() { return offset_of(ObjectMonitor, _Responsible); } static int Spinner_offset_in_bytes() { return offset_of(ObjectMonitor, _Spinner); } + // ObjectMonitor references can be ORed with markOopDesc::monitor_value + // as part of the ObjectMonitor tagging mechanism. When we combine an + // ObjectMonitor reference with an offset, we need to remove the tag + // value in order to generate the proper address. + // + // We can either adjust the ObjectMonitor reference and then add the + // offset or we can adjust the offset that is added to the ObjectMonitor + // reference. The latter avoids an AGI (Address Generation Interlock) + // stall so the helper macro adjusts the offset value that is returned + // to the ObjectMonitor reference manipulation code: + // + #define OM_OFFSET_NO_MONITOR_VALUE_TAG(f) \ + ((ObjectMonitor::f ## _offset_in_bytes()) - markOopDesc::monitor_value) + // Eventually we'll make provisions for multiple callbacks, but // now one will suffice. static int (*SpinCallbackFunction)(intptr_t, int); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/runtime/reflection.cpp --- a/hotspot/src/share/vm/runtime/reflection.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/runtime/reflection.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -806,17 +806,16 @@ oop Reflection::new_parameter(Handle method, int index, Symbol* sym, int flags, TRAPS) { - Handle name; - // A null symbol here translates to the empty string + Handle rh = java_lang_reflect_Parameter::create(CHECK_NULL); + if(NULL != sym) { - name = java_lang_String::create_from_symbol(sym, CHECK_NULL); + Handle name = java_lang_String::create_from_symbol(sym, CHECK_NULL); + java_lang_reflect_Parameter::set_name(rh(), name()); } else { - name = java_lang_String::create_from_str("", CHECK_NULL); + java_lang_reflect_Parameter::set_name(rh(), NULL); } - Handle rh = java_lang_reflect_Parameter::create(CHECK_NULL); - java_lang_reflect_Parameter::set_name(rh(), name()); java_lang_reflect_Parameter::set_modifiers(rh(), flags); java_lang_reflect_Parameter::set_executable(rh(), method()); java_lang_reflect_Parameter::set_index(rh(), index); diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp --- a/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -54,13 +54,17 @@ // Simple methods are as good being compiled with C1 as C2. // Determine if a given method is such a case. bool SimpleThresholdPolicy::is_trivial(Method* method) { - if (method->is_accessor()) return true; - if (method->code() != NULL) { - MethodData* mdo = method->method_data(); - if (mdo != NULL && mdo->num_loops() == 0 && - (method->code_size() < 5 || (mdo->num_blocks() < 4) && (method->code_size() < 15))) { - return !mdo->would_profile(); - } + if (method->is_accessor() || + method->is_constant_getter()) { + return true; + } + if (method->has_loops() || method->code_size() >= 15) { + return false; + } + MethodData* mdo = method->method_data(); + if (mdo != NULL && !mdo->would_profile() && + (method->code_size() < 5 || (mdo->num_blocks() < 4))) { + return true; } return false; } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/runtime/sweeper.hpp --- a/hotspot/src/share/vm/runtime/sweeper.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/runtime/sweeper.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -25,6 +25,8 @@ #ifndef SHARE_VM_RUNTIME_SWEEPER_HPP #define SHARE_VM_RUNTIME_SWEEPER_HPP +class WhiteBox; + #include "utilities/ticks.hpp" // An NmethodSweeper is an incremental cleaner for: // - cleanup inline caches @@ -52,6 +54,8 @@ // nmethod's space is freed. class NMethodSweeper : public AllStatic { + friend class WhiteBox; + private: static long _traversals; // Stack scan count, also sweep ID. static long _total_nof_code_cache_sweeps; // Total number of full sweeps of the code cache static long _time_counter; // Virtual time used to periodically invoke sweeper @@ -88,7 +92,6 @@ static void handle_safepoint_request(); static void do_stack_scanning(); static void possibly_sweep(); - public: static long traversal_count() { return _traversals; } static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/runtime/vmStructs.cpp --- a/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Nov 13 16:11:00 2014 -0800 @@ -527,12 +527,10 @@ nonstatic_field(DefNewGeneration, _next_gen, Generation*) \ nonstatic_field(DefNewGeneration, _tenuring_threshold, uint) \ nonstatic_field(DefNewGeneration, _age_table, ageTable) \ - nonstatic_field(DefNewGeneration, _eden_space, EdenSpace*) \ + nonstatic_field(DefNewGeneration, _eden_space, ContiguousSpace*) \ nonstatic_field(DefNewGeneration, _from_space, ContiguousSpace*) \ nonstatic_field(DefNewGeneration, _to_space, ContiguousSpace*) \ \ - nonstatic_field(EdenSpace, _gen, DefNewGeneration*) \ - \ nonstatic_field(Generation, _reserved, MemRegion) \ nonstatic_field(Generation, _virtual_space, VirtualSpace) \ nonstatic_field(Generation, _level, int) \ @@ -1490,7 +1488,6 @@ declare_toplevel_type(BitMap) \ declare_type(CompactibleSpace, Space) \ declare_type(ContiguousSpace, CompactibleSpace) \ - declare_type(EdenSpace, ContiguousSpace) \ declare_type(OffsetTableContigSpace, ContiguousSpace) \ declare_type(TenuredSpace, OffsetTableContigSpace) \ declare_toplevel_type(BarrierSet) \ @@ -1532,7 +1529,6 @@ declare_toplevel_type(CollectedHeap*) \ declare_toplevel_type(ContiguousSpace*) \ declare_toplevel_type(DefNewGeneration*) \ - declare_toplevel_type(EdenSpace*) \ declare_toplevel_type(GenCollectedHeap*) \ declare_toplevel_type(Generation*) \ declare_toplevel_type(GenerationSpec**) \ diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/services/mallocTracker.hpp --- a/hotspot/src/share/vm/services/mallocTracker.hpp Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/services/mallocTracker.hpp Thu Nov 13 16:11:00 2014 -0800 @@ -243,15 +243,15 @@ size_t _flags : 8; size_t _pos_idx : 16; size_t _bucket_idx: 40; -#define MAX_MALLOCSITE_TABLE_SIZE ((size_t)1 << 40) -#define MAX_BUCKET_LENGTH ((size_t)(1 << 16)) +#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(40) +#define MAX_BUCKET_LENGTH right_n_bits(16) #else size_t _size : 32; size_t _flags : 8; size_t _pos_idx : 8; size_t _bucket_idx: 16; -#define MAX_MALLOCSITE_TABLE_SIZE ((size_t)(1 << 16)) -#define MAX_BUCKET_LENGTH ((size_t)(1 << 8)) +#define MAX_MALLOCSITE_TABLE_SIZE right_n_bits(16) +#define MAX_BUCKET_LENGTH right_n_bits(8) #endif // _LP64 public: diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/src/share/vm/trace/traceEventClasses.xsl --- a/hotspot/src/share/vm/trace/traceEventClasses.xsl Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/src/share/vm/trace/traceEventClasses.xsl Thu Nov 13 16:11:00 2014 -0800 @@ -1,6 +1,6 @@ is :" + is); - System.out.println(" is.hash :" + is.hashCode()); - System.out.println(); - System.out.println(" e.name :" + e.getName()); - System.out.println(" e.hash :" + e.hashCode()); - System.out.println(" e.method :" + e.getMethod()); - System.out.println(" e.size :" + e.getSize()); - System.out.println(" e.csize :" + e.getCompressedSize()); + try (final InputStream is = zf.getInputStream(e)) { + try { + while (is.read(bytes) >= 0) { + } + } catch (IOException x) { + System.out.println(".................................."); + System.out.println(" --> is :" + is); + System.out.println(" is.hash :" + is.hashCode()); + System.out.println(); + System.out.println(" e.name :" + e.getName()); + System.out.println(" e.hash :" + e.hashCode()); + System.out.println(" e.method :" + e.getMethod()); + System.out.println(" e.size :" + e.getSize()); + System.out.println(" e.csize :" + e.getCompressedSize()); + System.out.println(".................................."); - x.printStackTrace(); - System.out.println(".................................."); - System.exit(97); + throw new AssertionError("IOException was throwing while read the archive. Test failed.", x); + } + } } } - zf.close(); + System.out.println("Test passed."); + } + + private static void createTestJarFile() { + ArrayList jarOptions = new ArrayList<>(); + + // jar cf foo.jar * + System.out.println("Creating jar file.."); + jarOptions.add("cf"); + jarOptions.add(JAR_NAME); + try { + for (int i = 0; i < 100; ++i) { + Path temp = Files.createTempFile(CURRENT_DIR, SELF_NAME, ".java"); + Files.copy(TEST_SOURCE_PATH, temp, StandardCopyOption.REPLACE_EXISTING); + jarOptions.add(temp.toString()); + } + } catch (IOException ex) { + throw new AssertionError("TESTBUG: Creating temp files failed.", ex); + } + runJar(jarOptions); + + // jar -uf0 foo.jar Test7068051.java + System.out.println("Adding unpacked file..."); + jarOptions.clear(); + jarOptions.add("-uf0"); + jarOptions.add(JAR_NAME); + jarOptions.add(TEST_SOURCE_PATH.toString()); + runJar(jarOptions); + } + + private static void runJar(List params) { + JDKToolLauncher jar = JDKToolLauncher.create("jar"); + for (String p : params) { + jar.addToolArg(p); + } + ProcessBuilder pb = new ProcessBuilder(jar.getCommand()); + try { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + } catch (IOException ex) { + throw new AssertionError("TESTBUG: jar failed.", ex); + } } } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/compiler/7068051/Test7068051.sh --- a/hotspot/test/compiler/7068051/Test7068051.sh Wed Jul 05 20:07:55 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2011, 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. -# -# -## 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 - -set -x - -${COMPILEJAVA}/bin/jar xf ${COMPILEJAVA}/jre/lib/javaws.jar -${COMPILEJAVA}/bin/jar cf foo.jar * -cp ${TESTSRC}/Test7068051.java ./ -${COMPILEJAVA}/bin/jar -uf0 foo.jar Test7068051.java - -${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test7068051.java - -${TESTJAVA}/bin/java ${TESTOPTS} -showversion -Xbatch Test7068051 foo.jar - diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/compiler/EliminateAutoBox/UnsignedLoads.java --- a/hotspot/test/compiler/EliminateAutoBox/UnsignedLoads.java Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/test/compiler/EliminateAutoBox/UnsignedLoads.java Thu Nov 13 16:11:00 2014 -0800 @@ -26,7 +26,7 @@ /* * @test * @library /testlibrary - * @run main/othervm -Xbatch -XX:+EliminateAutoBox + * @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox * -XX:CompileOnly=::valueOf,::byteValue,::shortValue,::testUnsignedByte,::testUnsignedShort * UnsignedLoads */ diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java Thu Nov 13 16:11:00 2014 -0800 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 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. + * + */ + +import java.lang.management.MemoryPoolMXBean; +import java.util.EnumSet; +import java.util.ArrayList; + +import sun.hotspot.WhiteBox; +import sun.hotspot.code.BlobType; +import com.oracle.java.testlibrary.Asserts; + +/* + * @test AllocationCodeBlobTest + * @bug 8059624 + * @library /testlibrary /testlibrary/whitebox + * @build AllocationCodeBlobTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* + * -XX:-SegmentedCodeCache AllocationCodeBlobTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* + * -XX:+SegmentedCodeCache AllocationCodeBlobTest + * @summary testing of WB::allocate/freeCodeBlob() + */ +public class AllocationCodeBlobTest { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final long CODE_CACHE_SIZE + = WHITE_BOX.getUintxVMFlag("ReservedCodeCacheSize"); + private static final int SIZE = 1; + + public static void main(String[] args) { + // check that Sweeper handels dummy blobs correctly + new ForcedSweeper(500).start(); + EnumSet blobTypes = BlobType.getAvailable(); + for (BlobType type : blobTypes) { + new AllocationCodeBlobTest(type).test(); + } + } + + private final BlobType type; + private final MemoryPoolMXBean bean; + private AllocationCodeBlobTest(BlobType type) { + this.type = type; + bean = type.getMemoryPool(); + } + + private void test() { + System.out.printf("type %s%n", type); + long start = getUsage(); + long addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id); + Asserts.assertNE(0, addr, "allocation failed"); + + long firstAllocation = getUsage(); + Asserts.assertLTE(start + SIZE, firstAllocation, + "allocation should increase memory usage: " + + start + " + " + SIZE + " <= " + firstAllocation); + + WHITE_BOX.freeCodeBlob(addr); + long firstFree = getUsage(); + Asserts.assertLTE(firstFree, firstAllocation, + "free shouldn't increase memory usage: " + + firstFree + " <= " + firstAllocation); + + addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id); + Asserts.assertNE(0, addr, "allocation failed"); + + long secondAllocation = getUsage(); + Asserts.assertEQ(firstAllocation, secondAllocation); + + WHITE_BOX.freeCodeBlob(addr); + System.out.println("allocating till possible..."); + ArrayList blobs = new ArrayList<>(); + int size = (int) (CODE_CACHE_SIZE >> 7); + while ((addr = WHITE_BOX.allocateCodeBlob(size, type.id)) != 0) { + blobs.add(addr); + } + for (Long blob : blobs) { + WHITE_BOX.freeCodeBlob(blob); + } + } + + private long getUsage() { + return bean.getUsage().getUsed(); + } + + private static class ForcedSweeper extends Thread { + private final int millis; + public ForcedSweeper(int millis) { + super("ForcedSweeper"); + setDaemon(true); + this.millis = millis; + } + public void run() { + try { + while (true) { + WHITE_BOX.forceNMethodSweep(); + Thread.sleep(millis); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new Error(e); + } + } + } +} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/compiler/whitebox/GetCodeHeapEntriesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/whitebox/GetCodeHeapEntriesTest.java Thu Nov 13 16:11:00 2014 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 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. + * + */ + +import java.util.Arrays; +import java.util.EnumSet; + +import sun.hotspot.WhiteBox; +import sun.hotspot.code.CodeBlob; +import sun.hotspot.code.BlobType; +import com.oracle.java.testlibrary.Asserts; + +/* + * @test GetCodeHeapEntriesTest + * @bug 8059624 + * @library /testlibrary /testlibrary/whitebox + * @build GetCodeHeapEntriesTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache + * GetCodeHeapEntriesTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache + * GetCodeHeapEntriesTest + * @summary testing of WB::getCodeHeapEntries() + */ +public class GetCodeHeapEntriesTest { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final int SIZE = 1024; + private static final String DUMMY_NAME = "WB::DummyBlob"; + private static EnumSet SEGMENTED_TYPES + = EnumSet.complementOf(EnumSet.of(BlobType.All)); + + public static void main(String[] args) { + EnumSet blobTypes = BlobType.getAvailable(); + for (BlobType type : blobTypes) { + new GetCodeHeapEntriesTest(type).test(); + } + } + + private final BlobType type; + private GetCodeHeapEntriesTest(BlobType type) { + this.type = type; + } + + private void test() { + System.out.printf("type %s%n", type); + long addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id); + Asserts.assertNE(0, addr, "allocation failed"); + CodeBlob[] blobs = CodeBlob.getCodeBlobs(type); + Asserts.assertNotNull(blobs); + CodeBlob blob = Arrays.stream(blobs) + .filter(GetCodeHeapEntriesTest::filter) + .findAny() + .get(); + Asserts.assertNotNull(blob); + Asserts.assertEQ(blob.code_blob_type, type); + Asserts.assertGTE(blob.size, SIZE); + + WHITE_BOX.freeCodeBlob(addr); + blobs = CodeBlob.getCodeBlobs(type); + long count = Arrays.stream(blobs) + .filter(GetCodeHeapEntriesTest::filter) + .count(); + Asserts.assertEQ(0L, count); + } + + private static boolean filter(CodeBlob blob) { + if (blob == null) { + return false; + } + return DUMMY_NAME.equals(blob.name); + } +} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/compiler/whitebox/GetNMethodTest.java --- a/hotspot/test/compiler/whitebox/GetNMethodTest.java Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/test/compiler/whitebox/GetNMethodTest.java Thu Nov 13 16:11:00 2014 -0800 @@ -22,7 +22,9 @@ * */ +import sun.hotspot.code.BlobType; import sun.hotspot.code.NMethod; +import com.oracle.java.testlibrary.Asserts; /* * @test GetNMethodTest @@ -52,21 +54,46 @@ compile(); checkCompiled(); + NMethod nmethod = NMethod.get(method, testCase.isOsr()); if (IS_VERBOSE) { System.out.println("nmethod = " + nmethod); } - if (nmethod == null) { - throw new RuntimeException("nmethod of compiled method is null"); + Asserts.assertNotNull(nmethod, + "nmethod of compiled method is null"); + Asserts.assertNotNull(nmethod.insts, + "nmethod.insts of compiled method is null"); + Asserts.assertGT(nmethod.insts.length, 0, + "compiled method's instructions is empty"); + Asserts.assertNotNull(nmethod.code_blob_type, "blob type is null"); + if (WHITE_BOX.getBooleanVMFlag("SegmentedCodeCache")) { + Asserts.assertNE(nmethod.code_blob_type, BlobType.All); + switch (nmethod.comp_level) { + case 1: + case 4: + checkBlockType(nmethod, BlobType.MethodNonProfiled); + break; + case 2: + case 3: + checkBlockType(nmethod, BlobType.MethodNonProfiled); + break; + default: + throw new Error("unexpected comp level " + nmethod); + } + } else { + Asserts.assertEQ(nmethod.code_blob_type, BlobType.All); } - if (nmethod.insts.length == 0) { - throw new RuntimeException("compiled method's instructions is empty"); - } + deoptimize(); checkNotCompiled(); nmethod = NMethod.get(method, testCase.isOsr()); - if (nmethod != null) { - throw new RuntimeException("nmethod of non-compiled method isn't null"); - } + Asserts.assertNull(nmethod, + "nmethod of non-compiled method isn't null"); + } + + private void checkBlockType(NMethod nmethod, BlobType expectedType) { + Asserts.assertEQ(nmethod.code_blob_type, expectedType, + String.format("blob_type[%s] for %d level isn't %s", + nmethod.code_blob_type, nmethod.comp_level, expectedType)); } } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/compiler/whitebox/IsMethodCompilableTest.java --- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java Thu Nov 13 16:11:00 2014 -0800 @@ -29,7 +29,7 @@ * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform - * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest + * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest * @summary testing of WB::isMethodCompilable() * @author igor.ignatyev@oracle.com */ diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/compiler/whitebox/LockCompilationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/whitebox/LockCompilationTest.java Thu Nov 13 16:11:00 2014 -0800 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 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 LockCompilationTest + * @bug 8059624 + * @library /testlibrary /testlibrary/whitebox + * @build LockCompilationTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* LockCompilationTest + * @summary testing of WB::lock/unlockCompilation() + */ + +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; + +import com.oracle.java.testlibrary.Asserts; + +public class LockCompilationTest extends CompilerWhiteBoxTest { + public static void main(String[] args) throws Exception { + CompilerWhiteBoxTest.main(LockCompilationTest::new, args); + } + + private LockCompilationTest(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + protected void test() throws Exception { + checkNotCompiled(); + + System.out.println("locking compilation"); + WHITE_BOX.lockCompilation(); + + try { + System.out.println("trying to compile"); + compile(); + // to check if it works correctly w/ safepoints + System.out.println("going to safepoint"); + WHITE_BOX.fullGC(); + waitBackgroundCompilation(); + Asserts.assertTrue( + WHITE_BOX.isMethodQueuedForCompilation(method), + method + " must be in queue"); + Asserts.assertFalse( + WHITE_BOX.isMethodCompiled(method, false), + method + " must be not compiled"); + Asserts.assertEQ( + WHITE_BOX.getMethodCompilationLevel(method, false), 0, + method + " comp_level must be == 0"); + Asserts.assertFalse( + WHITE_BOX.isMethodCompiled(method, true), + method + " must be not osr_compiled"); + Asserts.assertEQ( + WHITE_BOX.getMethodCompilationLevel(method, true), 0, + method + " osr_comp_level must be == 0"); + } finally { + System.out.println("unlocking compilation"); + WHITE_BOX.unlockCompilation(); + } + waitBackgroundCompilation(); + Asserts.assertFalse( + WHITE_BOX.isMethodQueuedForCompilation(method), + method + " must not be in queue"); + } +} + diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/gc/TestNUMAPageSize.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/TestNUMAPageSize.java Thu Nov 13 16:11:00 2014 -0800 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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 TestNUMAPageSize + * @summary Make sure that start up with NUMA support does not cause problems. + * @bug 8061467 + * @key gc + * @key regression + * @run main/othervm -Xmx8M -XX:+UseNUMA TestNUMAPageSize + */ + +public class TestNUMAPageSize { + public static void main(String args[]) throws Exception { + // nothing to do + } +} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/gc/concurrentMarkSweep/DisableResizePLAB.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/gc/concurrentMarkSweep/DisableResizePLAB.java Thu Nov 13 16:11:00 2014 -0800 @@ -0,0 +1,44 @@ +/* +* Copyright (c) 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 DisableResizePLAB + * @key gc + * @bug 8060467 + * @author filipp.zhinkin@oracle.com, john.coomes@oracle.com + * @summary Run CMS with PLAB resizing disabled and a small OldPLABSize + * @run main/othervm -XX:+UseConcMarkSweepGC -XX:-ResizePLAB -XX:OldPLABSize=1k -Xmx256m -XX:+PrintGCDetails DisableResizePLAB + */ + +public class DisableResizePLAB { + public static void main(String args[]) throws Exception { + Object garbage[] = new Object[1_000]; + for (int i = 0; i < garbage.length; i++) { + garbage[i] = new byte[0]; + } + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < 10_000) { + Object o = new byte[1024]; + } + } +} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/gc/g1/TestShrinkAuxiliaryData.java --- a/hotspot/test/gc/g1/TestShrinkAuxiliaryData.java Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/test/gc/g1/TestShrinkAuxiliaryData.java Thu Nov 13 16:11:00 2014 -0800 @@ -279,8 +279,7 @@ "-XX:\\+UseConcMarkSweepGC", "-XX:\\+UseParallelOldGC", "-XX:\\+UseParNewGC", - "-Xconcgc", - "-Xincgc" + "-Xconcgc" }; } } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/gc/startup_warnings/TestCMSIncrementalMode.java --- a/hotspot/test/gc/startup_warnings/TestCMSIncrementalMode.java Wed Jul 05 20:07:55 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ - -/* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. -* 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 TestCMSIncrementalMode -* @key gc -* @bug 8006398 -* @summary Test that the deprecated CMSIncrementalMode print a warning message -* @library /testlibrary -*/ - -import com.oracle.java.testlibrary.OutputAnalyzer; -import com.oracle.java.testlibrary.ProcessTools; - -public class TestCMSIncrementalMode { - - public static void main(String args[]) throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseConcMarkSweepGC", "-XX:+CMSIncrementalMode", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("warning: Using incremental CMS is deprecated and will likely be removed in a future release"); - output.shouldNotContain("error"); - output.shouldHaveExitValue(0); - } - -} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/gc/startup_warnings/TestCMSNoIncrementalMode.java --- a/hotspot/test/gc/startup_warnings/TestCMSNoIncrementalMode.java Wed Jul 05 20:07:55 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. -* 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 TestCMSNoIncrementalMode -* @key gc -* @bug 8006398 -* @summary Test that CMS with incremental mode turned off does not print a warning message -* @library /testlibrary -*/ - -import com.oracle.java.testlibrary.OutputAnalyzer; -import com.oracle.java.testlibrary.ProcessTools; - -public class TestCMSNoIncrementalMode { - - public static void main(String args[]) throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseConcMarkSweepGC", "-XX:-CMSIncrementalMode", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotContain("deprecated"); - output.shouldNotContain("error"); - output.shouldHaveExitValue(0); - } - -} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/gc/startup_warnings/TestIncGC.java --- a/hotspot/test/gc/startup_warnings/TestIncGC.java Wed Jul 05 20:07:55 2017 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* -* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. -* 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 TestIncGC -* @key gc -* @bug 8006398 -* @summary Test that the deprecated -Xincgc print a warning message -* @library /testlibrary -*/ - -import com.oracle.java.testlibrary.OutputAnalyzer; -import com.oracle.java.testlibrary.ProcessTools; - - -public class TestIncGC { - - public static void main(String args[]) throws Exception { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xincgc", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("warning: Using incremental CMS is deprecated and will likely be removed in a future release"); - output.shouldNotContain("error"); - output.shouldHaveExitValue(0); - } - -} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/runtime/NMT/MallocSiteHashOverflow.java --- a/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/test/runtime/NMT/MallocSiteHashOverflow.java Thu Nov 13 16:11:00 2014 -0800 @@ -27,7 +27,6 @@ * @requires sun.arch.data.model == "32" * @key nmt jcmd stress * @library /testlibrary /testlibrary/whitebox - * @ignore 8062870 * @build MallocSiteHashOverflow * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocSiteHashOverflow diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/runtime/NMT/MallocTrackingVerify.java --- a/hotspot/test/runtime/NMT/MallocTrackingVerify.java Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/test/runtime/NMT/MallocTrackingVerify.java Thu Nov 13 16:11:00 2014 -0800 @@ -27,7 +27,6 @@ * @summary Test to verify correctness of malloc tracking * @key nmt jcmd * @library /testlibrary /testlibrary/whitebox - * @ignore 8058251 * @build MallocTrackingVerify * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocTrackingVerify diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/runtime/contended/OopMapsSameGroup.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/runtime/contended/OopMapsSameGroup.java Thu Nov 13 16:11:00 2014 -0800 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.lang.Class; +import java.lang.String; +import java.lang.System; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import sun.misc.Unsafe; +import sun.misc.Contended; + +/* + * @test + * @bug 8015272 + * @summary \@Contended within the same group to use the same oop map + * + * @run main/othervm -XX:-RestrictContended -XX:ContendedPaddingWidth=128 -Xmx128m OopMapsSameGroup + */ +public class OopMapsSameGroup { + + public static final int COUNT = 10000; + + public static void main(String[] args) throws Exception { + Object o01 = new Object(); + Object o02 = new Object(); + Object o03 = new Object(); + Object o04 = new Object(); + + R[] rs = new R[COUNT]; + + for (int i = 0; i < COUNT; i++) { + R r = new R(); + r.o01 = o01; + r.o02 = o02; + r.o03 = o03; + r.o04 = o04; + rs[i] = r; + } + + System.gc(); + + for (int i = 0; i < COUNT; i++) { + R r = rs[i]; + if (r.o01 != o01) throw new Error("Test Error: o01"); + if (r.o02 != o02) throw new Error("Test Error: o02"); + if (r.o03 != o03) throw new Error("Test Error: o03"); + if (r.o04 != o04) throw new Error("Test Error: o04"); + } + } + + public static class R { + @Contended("group1") + Object o01; + + @Contended("group1") + Object o02; + + @Contended("group2") + Object o03; + + @Contended("group2") + Object o04; + } + +} + diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Thu Nov 13 16:11:00 2014 -0800 @@ -143,8 +143,14 @@ } public native boolean enqueueMethodForCompilation(Executable method, int compLevel, int entry_bci); public native void clearMethodState(Executable method); + public native void lockCompilation(); + public native void unlockCompilation(); public native int getMethodEntryBci(Executable method); public native Object[] getNMethod(Executable method, boolean isOsr); + public native long allocateCodeBlob(int size, int type); + public native void freeCodeBlob(long addr); + public native void forceNMethodSweep(); + public native Object[] getCodeHeapEntries(int type); // Intered strings public native boolean isInStringTable(String str); @@ -207,4 +213,13 @@ .findAny() .orElse(null); } + public native int getOffsetForName0(String name); + public int getOffsetForName(String name) throws Exception { + int offset = getOffsetForName0(name); + if (offset == -1) { + throw new RuntimeException(name + " not found"); + } + return offset; + } + } diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/testlibrary/whitebox/sun/hotspot/code/BlobType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/BlobType.java Thu Nov 13 16:11:00 2014 -0800 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 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. + * + */ + +package sun.hotspot.code; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; +import java.util.EnumSet; + +import sun.hotspot.WhiteBox; + +public enum BlobType { + // Execution level 1 and 4 (non-profiled) nmethods (including native nmethods) + MethodNonProfiled(0, "CodeHeap 'non-profiled nmethods'"), + // Execution level 2 and 3 (profiled) nmethods + MethodProfiled(1, "CodeHeap 'profiled nmethods'"), + // Non-nmethods like Buffers, Adapters and Runtime Stubs + NonNMethod(2, "CodeHeap 'non-nmethods'"), + // All types (No code cache segmentation) + All(3, "CodeCache"); + + public final int id; + private final String beanName; + + private BlobType(int id, String beanName) { + this.id = id; + this.beanName = beanName; + } + + public MemoryPoolMXBean getMemoryPool() { + for (MemoryPoolMXBean bean : ManagementFactory.getMemoryPoolMXBeans()) { + String name = bean.getName(); + if (beanName.equals(name)) { + return bean; + } + } + return null; + } + public static EnumSet getAvailable() { + WhiteBox whiteBox = WhiteBox.getWhiteBox(); + if (!whiteBox.getBooleanVMFlag("SegmentedCodeCache")) { + // only All for non segmented world + return EnumSet.of(All); + } + if (System.getProperty("java.vm.info").startsWith("interpreted ")) { + // only NonNMethod for -Xint + return EnumSet.of(NonNMethod); + } + + EnumSet result = EnumSet.complementOf(EnumSet.of(All)); + if (!whiteBox.getBooleanVMFlag("TieredCompilation") + || whiteBox.getIntxVMFlag("TieredStopAtLevel") <= 1) { + // there is no MethodProfiled in non tiered world or pure C1 + result.remove(MethodProfiled); + } + return result; + } +} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/testlibrary/whitebox/sun/hotspot/code/CodeBlob.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/CodeBlob.java Thu Nov 13 16:11:00 2014 -0800 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 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. + * + */ + +package sun.hotspot.code; + +import sun.hotspot.WhiteBox; + +public class CodeBlob { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + public static CodeBlob[] getCodeBlobs(BlobType type) { + Object[] obj = WB.getCodeHeapEntries(type.id); + if (obj == null) { + return null; + } + CodeBlob[] result = new CodeBlob[obj.length]; + for (int i = 0, n = result.length; i < n; ++i) { + result[i] = new CodeBlob((Object[]) obj[i]); + } + return result; + } + protected CodeBlob(Object[] obj) { + assert obj.length == 3; + name = (String) obj[0]; + size = (Integer) obj[1]; + code_blob_type = BlobType.values()[(Integer) obj[2]]; + assert code_blob_type.id == (Integer) obj[2]; + } + public final String name; + public final int size; + public final BlobType code_blob_type; + + @Override + public String toString() { + return "CodeBlob{" + + "name=" + name + + ", size=" + size + + ", code_blob_type=" + code_blob_type + + '}'; + } +} diff -r 82f4cb44b2d7 -r 74c92bdda9b5 hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java --- a/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java Wed Jul 05 20:07:55 2017 +0200 +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java Thu Nov 13 16:11:00 2014 -0800 @@ -27,28 +27,30 @@ import java.lang.reflect.Executable; import sun.hotspot.WhiteBox; -public class NMethod { +public class NMethod extends CodeBlob { private static final WhiteBox wb = WhiteBox.getWhiteBox(); public static NMethod get(Executable method, boolean isOsr) { Object[] obj = wb.getNMethod(method, isOsr); return obj == null ? null : new NMethod(obj); } private NMethod(Object[] obj) { - assert obj.length == 3; - comp_level = (Integer) obj[0]; - insts = (byte[]) obj[1]; - compile_id = (Integer) obj[2]; + super((Object[])obj[0]); + assert obj.length == 4; + comp_level = (Integer) obj[1]; + insts = (byte[]) obj[2]; + compile_id = (Integer) obj[3]; } - public byte[] insts; - public int comp_level; - public int compile_id; + public final byte[] insts; + public final int comp_level; + public final int compile_id; @Override public String toString() { - return "NMethod{" + - "insts=" + insts + - ", comp_level=" + comp_level + - ", compile_id=" + compile_id + - '}'; + return "NMethod{" + + super.toString() + + ", insts=" + insts + + ", comp_level=" + comp_level + + ", compile_id=" + compile_id + + '}'; } }