--- a/hotspot/agent/make/Makefile Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/make/Makefile Thu Jun 25 09:48:50 2015 -0700
@@ -58,6 +58,7 @@
sun.jvm.hotspot.debugger.dummy \
sun.jvm.hotspot.debugger.linux \
sun.jvm.hotspot.debugger.linux.amd64 \
+sun.jvm.hotspot.debugger.linux.aarch64 \
sun.jvm.hotspot.debugger.linux.ppc64 \
sun.jvm.hotspot.debugger.linux.x86 \
sun.jvm.hotspot.debugger.posix \
@@ -65,6 +66,7 @@
sun.jvm.hotspot.debugger.ppc64 \
sun.jvm.hotspot.debugger.proc \
sun.jvm.hotspot.debugger.proc.amd64 \
+sun.jvm.hotspot.debugger.proc.aarch64 \
sun.jvm.hotspot.debugger.proc.ppc64 \
sun.jvm.hotspot.debugger.proc.sparc \
sun.jvm.hotspot.debugger.proc.x86 \
@@ -91,11 +93,13 @@
sun.jvm.hotspot.prims \
sun.jvm.hotspot.runtime \
sun.jvm.hotspot.runtime.amd64 \
+sun.jvm.hotspot.runtime.aarch64 \
sun.jvm.hotspot.runtime.bsd \
sun.jvm.hotspot.runtime.bsd_amd64 \
sun.jvm.hotspot.runtime.bsd_x86 \
sun.jvm.hotspot.runtime.linux \
sun.jvm.hotspot.runtime.linux_amd64 \
+sun.jvm.hotspot.runtime.linux_aarch64 \
sun.jvm.hotspot.runtime.linux_ppc64 \
sun.jvm.hotspot.runtime.linux_sparc \
sun.jvm.hotspot.runtime.linux_x86 \
@@ -149,16 +153,19 @@
sun/jvm/hotspot/debugger/linux/*.java \
sun/jvm/hotspot/debugger/linux/ppc64/*.java \
sun/jvm/hotspot/debugger/linux/x86/*.java \
+sun/jvm/hotspot/debugger/linux/aarch64/*.java \
sun/jvm/hotspot/debugger/posix/*.java \
sun/jvm/hotspot/debugger/posix/elf/*.java \
sun/jvm/hotspot/debugger/ppc64/*.java \
sun/jvm/hotspot/debugger/proc/*.java \
sun/jvm/hotspot/debugger/proc/amd64/*.java \
+sun/jvm/hotspot/debugger/proc/aarch64/*.java \
sun/jvm/hotspot/debugger/proc/ppc64/*.java \
sun/jvm/hotspot/debugger/proc/sparc/*.java \
sun/jvm/hotspot/debugger/proc/x86/*.java \
sun/jvm/hotspot/debugger/remote/*.java \
sun/jvm/hotspot/debugger/remote/amd64/*.java \
+sun/jvm/hotspot/debugger/remote/aarch64/*.java \
sun/jvm/hotspot/debugger/remote/ppc64/*.java \
sun/jvm/hotspot/debugger/remote/sparc/*.java \
sun/jvm/hotspot/debugger/remote/x86/*.java \
@@ -178,11 +185,13 @@
sun/jvm/hotspot/prims/*.java \
sun/jvm/hotspot/runtime/*.java \
sun/jvm/hotspot/runtime/amd64/*.java \
+sun/jvm/hotspot/runtime/aarch64/*.java \
sun/jvm/hotspot/runtime/bsd/*.java \
sun/jvm/hotspot/runtime/bsd_amd64/*.java \
sun/jvm/hotspot/runtime/bsd_x86/*.java \
sun/jvm/hotspot/runtime/linux/*.java \
sun/jvm/hotspot/runtime/linux_amd64/*.java \
+sun/jvm/hotspot/runtime/linux_aarch64/*.java \
sun/jvm/hotspot/runtime/linux_ppc64/*.java \
sun/jvm/hotspot/runtime/linux_sparc/*.java \
sun/jvm/hotspot/runtime/linux_x86/*.java \
--- a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c Thu Jun 25 09:48:50 2015 -0700
@@ -53,6 +53,10 @@
#include "sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext.h"
#endif
+#ifdef aarch64
+#include "sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext.h"
+#endif
+
static jfieldID p_ps_prochandle_ID = 0;
static jfieldID threadList_ID = 0;
static jfieldID loadObjectList_ID = 0;
@@ -368,7 +372,7 @@
#define NPRGREG sun_jvm_hotspot_debugger_amd64_AMD64ThreadContext_NPRGREG
#endif
#ifdef aarch64
-#define NPRGREG 32
+#define NPRGREG sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_NPRGREG
#endif
#if defined(sparc) || defined(sparcv9)
#define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG
@@ -473,6 +477,13 @@
#define REG_INDEX(reg) sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_##reg
+ {
+ int i;
+ for (i = 0; i < 31; i++)
+ regs[i] = gregs.regs[i];
+ regs[REG_INDEX(SP)] = gregs.sp;
+ regs[REG_INDEX(PC)] = gregs.pc;
+ }
#endif /* aarch64 */
#ifdef ppc64
--- a/hotspot/agent/src/os/linux/Makefile Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/os/linux/Makefile Thu Jun 25 09:48:50 2015 -0700
@@ -53,14 +53,15 @@
$(JAVAH) -jni -classpath ../../../build/classes -d $(ARCH) \
sun.jvm.hotspot.debugger.x86.X86ThreadContext \
sun.jvm.hotspot.debugger.sparc.SPARCThreadContext \
- sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext
+ sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext \
+ sun.jvm.hotspot.debugger.aarch64.AARCH64ThreadContext
$(GCC) $(CFLAGS) $< -o $@
$(ARCH)/sadis.o: ../../share/native/sadis.c
$(JAVAH) -jni -classpath ../../../build/classes -d $(ARCH) \
sun.jvm.hotspot.asm.Disassembler
$(GCC) $(CFLAGS) $< -o $@
-
+
$(ARCH)/%.o: %.c
$(GCC) $(CFLAGS) $< -o $@
--- a/hotspot/agent/src/os/linux/libproc.h Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/os/linux/libproc.h Thu Jun 25 09:48:50 2015 -0700
@@ -72,6 +72,7 @@
#define user_regs_struct pt_regs
#endif
#if defined(aarch64)
+#include <asm/ptrace.h>
#define user_regs_struct user_pt_regs
#endif
--- a/hotspot/agent/src/os/linux/proc_service.h Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/os/linux/proc_service.h Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
// Linux does not have the proc service library, though it does provide the
// thread_db library which can be used to manipulate threads without having
-// to know the details of LinuxThreads or NPTL
+// to know the details of NPTL
// copied from Solaris "proc_service.h"
typedef enum {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Thu Jun 25 09:48:50 2015 -0700
@@ -983,19 +983,15 @@
curFrame.getFP(),
anno));
} else {
- if (VM.getVM().getCPU().equals("x86") || VM.getVM().getCPU().equals("amd64")) {
- // For C2, which has null frame pointers on x86/amd64
- CodeBlob cb = VM.getVM().getCodeCache().findBlob(curFrame.getPC());
- Address sp = curFrame.getSP();
- if (Assert.ASSERTS_ENABLED) {
- Assert.that(cb.getFrameSize() > 0, "CodeBlob must have non-zero frame size");
- }
- annoPanel.addAnnotation(new Annotation(sp,
- sp.addOffsetTo(cb.getFrameSize()),
- anno));
- } else {
- Assert.that(VM.getVM().getCPU().equals("ia64"), "only ia64 should reach here");
+ // For C2, which has null frame pointers on x86/amd64/aarch64
+ CodeBlob cb = VM.getVM().getCodeCache().findBlob(curFrame.getPC());
+ Address sp = curFrame.getSP();
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(cb.getFrameSize() > 0, "CodeBlob must have non-zero frame size");
}
+ annoPanel.addAnnotation(new Annotation(sp,
+ sp.addOffsetTo(cb.getFrameSize()),
+ anno));
}
// Add interpreter frame annotations
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.debugger.aarch64;
+
+import java.lang.annotation.Native;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+
+/** Specifies the thread context on aarch64 platforms; only a sub-portion
+ * of the context is guaranteed to be present on all operating
+ * systems. */
+
+public abstract class AARCH64ThreadContext implements ThreadContext {
+ // Taken from /usr/include/asm/sigcontext.h on Linux/AARCH64.
+
+ // NOTE: the indices for the various registers must be maintained as
+ // listed across various operating systems. However, only a small
+ // subset of the registers' values are guaranteed to be present (and
+ // must be present for the SA's stack walking to work)
+
+ // One instance of the Native annotation is enough to trigger header generation
+ // for this file.
+ @Native
+ public static final int R0 = 0;
+ public static final int R1 = 1;
+ public static final int R2 = 2;
+ public static final int R3 = 3;
+ public static final int R4 = 4;
+ public static final int R5 = 5;
+ public static final int R6 = 6;
+ public static final int R7 = 7;
+ public static final int R8 = 8;
+ public static final int R9 = 9;
+ public static final int R10 = 10;
+ public static final int R11 = 11;
+ public static final int R12 = 12;
+ public static final int R13 = 13;
+ public static final int R14 = 14;
+ public static final int R15 = 15;
+ public static final int R16 = 16;
+ public static final int R17 = 17;
+ public static final int R18 = 18;
+ public static final int R19 = 19;
+ public static final int R20 = 20;
+ public static final int R21 = 21;
+ public static final int R22 = 22;
+ public static final int R23 = 23;
+ public static final int R24 = 24;
+ public static final int R25 = 25;
+ public static final int R26 = 26;
+ public static final int R27 = 27;
+ public static final int R28 = 28;
+ public static final int FP = 29;
+ public static final int LR = 30;
+ public static final int SP = 31;
+ public static final int PC = 32;
+
+ public static final int NPRGREG = 33;
+
+ private long[] data;
+
+ public AARCH64ThreadContext() {
+ data = new long[NPRGREG];
+ }
+
+ public int getNumRegisters() {
+ return NPRGREG;
+ }
+
+ public String getRegisterName(int index) {
+ switch (index) {
+ case LR: return "lr";
+ case SP: return "sp";
+ case PC: return "pc";
+ default:
+ return "r" + index;
+ }
+ }
+
+ public void setRegister(int index, long value) {
+ data[index] = value;
+ }
+
+ public long getRegister(int index) {
+ return data[index];
+ }
+
+ public CFrame getTopFrame(Debugger dbg) {
+ return null;
+ }
+
+ /** This can't be implemented in this class since we would have to
+ * tie the implementation to, for example, the debugging system */
+ public abstract void setRegisterAsAddress(int index, Address value);
+
+ /** This can't be implemented in this class since we would have to
+ * tie the implementation to, for example, the debugging system */
+ public abstract Address getRegisterAsAddress(int index);
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,12 +32,14 @@
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.x86.*;
import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
import sun.jvm.hotspot.debugger.sparc.*;
import sun.jvm.hotspot.debugger.ppc64.*;
import sun.jvm.hotspot.debugger.linux.x86.*;
import sun.jvm.hotspot.debugger.linux.amd64.*;
import sun.jvm.hotspot.debugger.linux.sparc.*;
import sun.jvm.hotspot.debugger.linux.ppc64.*;
+import sun.jvm.hotspot.debugger.linux.aarch64.*;
import sun.jvm.hotspot.utilities.*;
class LinuxCDebugger implements CDebugger {
@@ -106,6 +109,13 @@
Address pc = context.getRegisterAsAddress(PPC64ThreadContext.PC);
if (pc == null) return null;
return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize());
+ } else if (cpu.equals("aarch64")) {
+ AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext();
+ Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP);
+ if (fp == null) return null;
+ Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC);
+ if (pc == null) return null;
+ return new LinuxAARCH64CFrame(dbg, fp, pc);
} else {
// Runtime exception thrown by LinuxThreadContextFactory if unknown cpu
ThreadContext context = (ThreadContext) thread.getContext();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64CFrame.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.debugger.linux.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.linux.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+import sun.jvm.hotspot.debugger.cdbg.basic.*;
+
+final public class LinuxAARCH64CFrame extends BasicCFrame {
+ public LinuxAARCH64CFrame(LinuxDebugger dbg, Address fp, Address pc) {
+ super(dbg.getCDebugger());
+ this.fp = fp;
+ this.pc = pc;
+ this.dbg = dbg;
+ }
+
+ // override base class impl to avoid ELF parsing
+ public ClosestSymbol closestSymbolToPC() {
+ // try native lookup in debugger.
+ return dbg.lookup(dbg.getAddressValue(pc()));
+ }
+
+ public Address pc() {
+ return pc;
+ }
+
+ public Address localVariableBase() {
+ return fp;
+ }
+
+ public CFrame sender(ThreadProxy thread) {
+ AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext();
+ Address rsp = context.getRegisterAsAddress(AARCH64ThreadContext.SP);
+
+ if ((fp == null) || fp.lessThan(rsp)) {
+ return null;
+ }
+
+ // Check alignment of fp
+ if (dbg.getAddressValue(fp) % (2 * ADDRESS_SIZE) != 0) {
+ return null;
+ }
+
+ Address nextFP = fp.getAddressAt(0 * ADDRESS_SIZE);
+ if (nextFP == null || nextFP.lessThanOrEqual(fp)) {
+ return null;
+ }
+ Address nextPC = fp.getAddressAt(1 * ADDRESS_SIZE);
+ if (nextPC == null) {
+ return null;
+ }
+ return new LinuxAARCH64CFrame(dbg, nextFP, nextPC);
+ }
+
+ // package/class internals only
+ private static final int ADDRESS_SIZE = 8;
+ private Address pc;
+ private Address sp;
+ private Address fp;
+ private LinuxDebugger dbg;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/aarch64/LinuxAARCH64ThreadContext.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.debugger.linux.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.linux.*;
+
+public class LinuxAARCH64ThreadContext extends AARCH64ThreadContext {
+ private LinuxDebugger debugger;
+
+ public LinuxAARCH64ThreadContext(LinuxDebugger debugger) {
+ super();
+ this.debugger = debugger;
+ }
+
+ public void setRegisterAsAddress(int index, Address value) {
+ setRegister(index, debugger.getAddressValue(value));
+ }
+
+ public Address getRegisterAsAddress(int index) {
+ return debugger.newAddress(getRegister(index));
+ }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java Thu Jun 25 09:48:50 2015 -0700
@@ -31,11 +31,13 @@
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.proc.amd64.*;
+import sun.jvm.hotspot.debugger.proc.aarch64.*;
import sun.jvm.hotspot.debugger.proc.sparc.*;
import sun.jvm.hotspot.debugger.proc.ppc64.*;
import sun.jvm.hotspot.debugger.proc.x86.*;
import sun.jvm.hotspot.debugger.ppc64.*;
import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
import sun.jvm.hotspot.debugger.sparc.*;
import sun.jvm.hotspot.debugger.x86.*;
import sun.jvm.hotspot.utilities.*;
@@ -88,6 +90,10 @@
threadFactory = new ProcAMD64ThreadFactory(this);
pcRegIndex = AMD64ThreadContext.RIP;
fpRegIndex = AMD64ThreadContext.RBP;
+ } else if (cpu.equals("aarch64")) {
+ threadFactory = new ProcAARCH64ThreadFactory(this);
+ pcRegIndex = AARCH64ThreadContext.PC;
+ fpRegIndex = AARCH64ThreadContext.FP;
} else if (cpu.equals("ppc64")) {
threadFactory = new ProcPPC64ThreadFactory(this);
pcRegIndex = PPC64ThreadContext.PC;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64Thread.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.debugger.proc.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.proc.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class ProcAARCH64Thread implements ThreadProxy {
+ private ProcDebugger debugger;
+ private int id;
+
+ public ProcAARCH64Thread(ProcDebugger debugger, Address addr) {
+ this.debugger = debugger;
+
+ // FIXME: the size here should be configurable. However, making it
+ // so would produce a dependency on the "types" package from the
+ // debugger package, which is not desired.
+ this.id = (int) addr.getCIntegerAt(0, 4, true);
+ }
+
+ public ProcAARCH64Thread(ProcDebugger debugger, long id) {
+ this.debugger = debugger;
+ this.id = (int) id;
+ }
+
+ public ThreadContext getContext() throws IllegalThreadStateException {
+ ProcAARCH64ThreadContext context = new ProcAARCH64ThreadContext(debugger);
+ long[] regs = debugger.getThreadIntegerRegisterSet(id);
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(regs.length == AARCH64ThreadContext.NPRGREG, "size mismatch");
+ }
+ for (int i = 0; i < regs.length; i++) {
+ context.setRegister(i, regs[i]);
+ }
+ return context;
+ }
+
+ public boolean canSetContext() throws DebuggerException {
+ return false;
+ }
+
+ public void setContext(ThreadContext context)
+ throws IllegalThreadStateException, DebuggerException {
+ throw new DebuggerException("Unimplemented");
+ }
+
+ public String toString() {
+ return "t@" + id;
+ }
+
+ public boolean equals(Object obj) {
+ if ((obj == null) || !(obj instanceof ProcAARCH64Thread)) {
+ return false;
+ }
+
+ return (((ProcAARCH64Thread) obj).id == id);
+ }
+
+ public int hashCode() {
+ return id;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadContext.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.debugger.proc.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.proc.*;
+
+public class ProcAARCH64ThreadContext extends AARCH64ThreadContext {
+ private ProcDebugger debugger;
+
+ public ProcAARCH64ThreadContext(ProcDebugger debugger) {
+ super();
+ this.debugger = debugger;
+ }
+
+ public void setRegisterAsAddress(int index, Address value) {
+ setRegister(index, debugger.getAddressValue(value));
+ }
+
+ public Address getRegisterAsAddress(int index) {
+ return debugger.newAddress(getRegister(index));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/aarch64/ProcAARCH64ThreadFactory.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.debugger.proc.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.proc.*;
+
+public class ProcAARCH64ThreadFactory implements ProcThreadFactory {
+ private ProcDebugger debugger;
+
+ public ProcAARCH64ThreadFactory(ProcDebugger debugger) {
+ this.debugger = debugger;
+ }
+
+ public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) {
+ return new ProcAARCH64Thread(debugger, threadIdentifierAddr);
+ }
+
+ public ThreadProxy createThreadWrapper(long id) {
+ return new ProcAARCH64Thread(debugger, id);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64Thread.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.debugger.remote.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.remote.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class RemoteAARCH64Thread extends RemoteThread {
+ public RemoteAARCH64Thread(RemoteDebuggerClient debugger, Address addr) {
+ super(debugger, addr);
+ }
+
+ public RemoteAARCH64Thread(RemoteDebuggerClient debugger, long id) {
+ super(debugger, id);
+ }
+
+ public ThreadContext getContext() throws IllegalThreadStateException {
+ RemoteAARCH64ThreadContext context = new RemoteAARCH64ThreadContext(debugger);
+ long[] regs = (addr != null)? debugger.getThreadIntegerRegisterSet(addr) :
+ debugger.getThreadIntegerRegisterSet(id);
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(regs.length == AARCH64ThreadContext.NPRGREG, "size of register set must match");
+ }
+ for (int i = 0; i < regs.length; i++) {
+ context.setRegister(i, regs[i]);
+ }
+ return context;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadContext.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.debugger.remote.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.remote.*;
+
+public class RemoteAARCH64ThreadContext extends AARCH64ThreadContext {
+ private RemoteDebuggerClient debugger;
+
+ public RemoteAARCH64ThreadContext(RemoteDebuggerClient debugger) {
+ super();
+ this.debugger = debugger;
+ }
+
+ public void setRegisterAsAddress(int index, Address value) {
+ setRegister(index, debugger.getAddressValue(value));
+ }
+
+ public Address getRegisterAsAddress(int index) {
+ return debugger.newAddress(getRegister(index));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/aarch64/RemoteAARCH64ThreadFactory.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.debugger.remote.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.remote.*;
+
+public class RemoteAARCH64ThreadFactory implements RemoteThreadFactory {
+ private RemoteDebuggerClient debugger;
+
+ public RemoteAARCH64ThreadFactory(RemoteDebuggerClient debugger) {
+ this.debugger = debugger;
+ }
+
+ public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) {
+ return new RemoteAARCH64Thread(debugger, threadIdentifierAddr);
+ }
+
+ public ThreadProxy createThreadWrapper(long id) {
+ return new RemoteAARCH64Thread(debugger, id);
+ }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/Generation.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/gc/shared/Generation.java Thu Jun 25 09:48:50 2015 -0700
@@ -49,7 +49,6 @@
public abstract class Generation extends VMObject {
private static long reservedFieldOffset;
private static long virtualSpaceFieldOffset;
- private static CIntegerField levelField;
protected static final int K = 1024;
// Fields for class StatRecord
private static Field statRecordField;
@@ -75,7 +74,6 @@
reservedFieldOffset = type.getField("_reserved").getOffset();
virtualSpaceFieldOffset = type.getField("_virtual_space").getOffset();
- levelField = type.getCIntegerField("_level");
// StatRecord
statRecordField = type.getField("_stat_record");
type = db.lookupType("Generation::StatRecord");
@@ -130,14 +128,6 @@
}
}
- public GenerationSpec spec() {
- return ((GenCollectedHeap) VM.getVM().getUniverse().heap()).spec(level());
- }
-
- public int level() {
- return (int) levelField.getValue(addr);
- }
-
public int invocations() {
return getStatRecord().getInvocations();
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -357,12 +357,6 @@
// FIXME: avoiding implementing this for now if possible
// public void interpreter_frame_set_monitor_end(BasicObjectLock* value);
// public void interpreter_frame_verify_monitor(BasicObjectLock* value) const;
- //
- // Tells whether the current interpreter_frame frame pointer
- // corresponds to the old compiled/deoptimized fp
- // The receiver used to be a top level frame
- // public boolean interpreter_frame_equals_unpacked_fp(intptr_t* fp);
-
//--------------------------------------------------------------------------------
// Method and constant pool cache:
//
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java Thu Jun 25 09:48:50 2015 -0700
@@ -35,6 +35,7 @@
import sun.jvm.hotspot.runtime.win32_x86.Win32X86JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.linux_x86.LinuxX86JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.linux_amd64.LinuxAMD64JavaThreadPDAccess;
+import sun.jvm.hotspot.runtime.linux_aarch64.LinuxAARCH64JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.linux_ppc64.LinuxPPC64JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.linux_sparc.LinuxSPARCJavaThreadPDAccess;
import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess;
@@ -91,6 +92,8 @@
access = new LinuxSPARCJavaThreadPDAccess();
} else if (cpu.equals("ppc64")) {
access = new LinuxPPC64JavaThreadPDAccess();
+ } else if (cpu.equals("aarch64")) {
+ access = new LinuxAARCH64JavaThreadPDAccess();
} else {
try {
access = (JavaThreadPDAccess)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64CurrentFrameGuess.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.runtime.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.code.*;
+import sun.jvm.hotspot.interpreter.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.aarch64.*;
+
+/** <P> Should be able to be used on all aarch64 platforms we support
+ (Linux/aarch64) to implement JavaThread's "currentFrameGuess()"
+ functionality. Input is an AARCH64ThreadContext; output is SP, FP,
+ and PC for an AARCH64Frame. Instantiation of the AARCH64Frame is
+ left to the caller, since we may need to subclass AARCH64Frame to
+ support signal handler frames on Unix platforms. </P>
+
+ <P> Algorithm is to walk up the stack within a given range (say,
+ 512K at most) looking for a plausible PC and SP for a Java frame,
+ also considering those coming in from the context. If we find a PC
+ that belongs to the VM (i.e., in generated code like the
+ interpreter or CodeCache) then we try to find an associated FP.
+ We repeat this until we either find a complete frame or run out of
+ stack to look at. </P> */
+
+public class AARCH64CurrentFrameGuess {
+ private AARCH64ThreadContext context;
+ private JavaThread thread;
+ private Address spFound;
+ private Address fpFound;
+ private Address pcFound;
+
+ private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.aarch64.AARCH64Frame.DEBUG")
+ != null;
+
+ public AARCH64CurrentFrameGuess(AARCH64ThreadContext context,
+ JavaThread thread) {
+ this.context = context;
+ this.thread = thread;
+ }
+
+ /** Returns false if not able to find a frame within a reasonable range. */
+ public boolean run(long regionInBytesToSearch) {
+ Address sp = context.getRegisterAsAddress(AARCH64ThreadContext.SP);
+ Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC);
+ Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP);
+ if (sp == null) {
+ // Bail out if no last java frame either
+ if (thread.getLastJavaSP() != null) {
+ setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null);
+ return true;
+ }
+ return false;
+ }
+ Address end = sp.addOffsetTo(regionInBytesToSearch);
+ VM vm = VM.getVM();
+
+ setValues(null, null, null); // Assume we're not going to find anything
+
+ if (vm.isJavaPCDbg(pc)) {
+ if (vm.isClientCompiler()) {
+ // If the topmost frame is a Java frame, we are (pretty much)
+ // guaranteed to have a viable FP. We should be more robust
+ // than this (we have the potential for losing entire threads'
+ // stack traces) but need to see how much work we really have
+ // to do here. Searching the stack for an (SP, FP) pair is
+ // hard since it's easy to misinterpret inter-frame stack
+ // pointers as base-of-frame pointers; we also don't know the
+ // sizes of C1 frames (not registered in the nmethod) so can't
+ // derive them from SP.
+
+ setValues(sp, fp, pc);
+ return true;
+ } else {
+ if (vm.getInterpreter().contains(pc)) {
+ if (DEBUG) {
+ System.out.println("CurrentFrameGuess: choosing interpreter frame: sp = " +
+ sp + ", fp = " + fp + ", pc = " + pc);
+ }
+ setValues(sp, fp, pc);
+ return true;
+ }
+
+ // For the server compiler, FP is not guaranteed to be valid
+ // for compiled code. In addition, an earlier attempt at a
+ // non-searching algorithm (see below) failed because the
+ // stack pointer from the thread context was pointing
+ // (considerably) beyond the ostensible end of the stack, into
+ // garbage; walking from the topmost frame back caused a crash.
+ //
+ // This algorithm takes the current PC as a given and tries to
+ // find the correct corresponding SP by walking up the stack
+ // and repeatedly performing stackwalks (very inefficient).
+ //
+ // FIXME: there is something wrong with stackwalking across
+ // adapter frames...this is likely to be the root cause of the
+ // failure with the simpler algorithm below.
+
+ for (long offset = 0;
+ offset < regionInBytesToSearch;
+ offset += vm.getAddressSize()) {
+ try {
+ Address curSP = sp.addOffsetTo(offset);
+ Frame frame = new AARCH64Frame(curSP, null, pc);
+ RegisterMap map = thread.newRegisterMap(false);
+ while (frame != null) {
+ if (frame.isEntryFrame() && frame.entryFrameIsFirst()) {
+ // We were able to traverse all the way to the
+ // bottommost Java frame.
+ // This sp looks good. Keep it.
+ if (DEBUG) {
+ System.out.println("CurrentFrameGuess: Choosing sp = " + curSP + ", pc = " + pc);
+ }
+ setValues(curSP, null, pc);
+ return true;
+ }
+ frame = frame.sender(map);
+ }
+ } catch (Exception e) {
+ if (DEBUG) {
+ System.out.println("CurrentFrameGuess: Exception " + e + " at offset " + offset);
+ }
+ // Bad SP. Try another.
+ }
+ }
+
+ // Were not able to find a plausible SP to go with this PC.
+ // Bail out.
+ return false;
+
+ /*
+ // Original algorithm which does not work because SP was
+ // pointing beyond where it should have:
+
+ // For the server compiler, FP is not guaranteed to be valid
+ // for compiled code. We see whether the PC is in the
+ // interpreter and take care of that, otherwise we run code
+ // (unfortunately) duplicated from AARCH64Frame.senderForCompiledFrame.
+
+ CodeCache cc = vm.getCodeCache();
+ if (cc.contains(pc)) {
+ CodeBlob cb = cc.findBlob(pc);
+
+ // See if we can derive a frame pointer from SP and PC
+ // NOTE: This is the code duplicated from AARCH64Frame
+ Address saved_fp = null;
+ int llink_offset = cb.getLinkOffset();
+ if (llink_offset >= 0) {
+ // Restore base-pointer, since next frame might be an interpreter frame.
+ Address fp_addr = sp.addOffsetTo(VM.getVM().getAddressSize() * llink_offset);
+ saved_fp = fp_addr.getAddressAt(0);
+ }
+
+ setValues(sp, saved_fp, pc);
+ return true;
+ }
+ */
+ }
+ } else {
+ // If the current program counter was not known to us as a Java
+ // PC, we currently assume that we are in the run-time system
+ // and attempt to look to thread-local storage for saved SP and
+ // FP. Note that if these are null (because we were, in fact,
+ // in Java code, i.e., vtable stubs or similar, and the SA
+ // didn't have enough insight into the target VM to understand
+ // that) then we are going to lose the entire stack trace for
+ // the thread, which is sub-optimal. FIXME.
+
+ if (DEBUG) {
+ System.out.println("CurrentFrameGuess: choosing last Java frame: sp = " +
+ thread.getLastJavaSP() + ", fp = " + thread.getLastJavaFP());
+ }
+ if (thread.getLastJavaSP() == null) {
+ return false; // No known Java frames on stack
+ }
+
+ // The runtime has a nasty habit of not saving fp in the frame
+ // anchor, leaving us to grovel about in the stack to find a
+ // plausible address. Fortunately, this only happens in
+ // compiled code; there we always have a valid PC, and we always
+ // push LR and FP onto the stack as a pair, with FP at the lower
+ // address.
+ pc = thread.getLastJavaPC();
+ fp = thread.getLastJavaFP();
+ sp = thread.getLastJavaSP();
+
+ if (fp == null) {
+ CodeCache cc = vm.getCodeCache();
+ if (cc.contains(pc)) {
+ CodeBlob cb = cc.findBlob(pc);
+ if (DEBUG) {
+ System.out.println("FP is null. Found blob frame size " + cb.getFrameSize());
+ }
+ // See if we can derive a frame pointer from SP and PC
+ long link_offset = cb.getFrameSize() - 2 * VM.getVM().getAddressSize();
+ if (link_offset >= 0) {
+ fp = sp.addOffsetTo(link_offset);
+ }
+ }
+ }
+
+ setValues(sp, fp, null);
+
+ return true;
+ }
+ }
+
+ public Address getSP() { return spFound; }
+ public Address getFP() { return fpFound; }
+ /** May be null if getting values from thread-local storage; take
+ care to call the correct AARCH64Frame constructor to recover this if
+ necessary */
+ public Address getPC() { return pcFound; }
+
+ private void setValues(Address sp, Address fp, Address pc) {
+ spFound = sp;
+ fpFound = fp;
+ pcFound = pc;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64Frame.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,555 @@
+/*
+ * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.runtime.aarch64;
+
+import java.util.*;
+import sun.jvm.hotspot.code.*;
+import sun.jvm.hotspot.compiler.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.oops.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+/** Specialization of and implementation of abstract methods of the
+ Frame class for the aarch64 family of CPUs. */
+
+public class AARCH64Frame extends Frame {
+ private static final boolean DEBUG;
+ static {
+ DEBUG = System.getProperty("sun.jvm.hotspot.runtime.aarch64.AARCH64Frame.DEBUG") != null;
+ }
+
+ // All frames
+ private static final int LINK_OFFSET = 0;
+ private static final int RETURN_ADDR_OFFSET = 1;
+ private static final int SENDER_SP_OFFSET = 2;
+
+ // Interpreter frames
+ private static final int INTERPRETER_FRAME_MIRROR_OFFSET = 2; // for native calls only
+ private static final int INTERPRETER_FRAME_SENDER_SP_OFFSET = -1;
+ private static final int INTERPRETER_FRAME_LAST_SP_OFFSET = INTERPRETER_FRAME_SENDER_SP_OFFSET - 1;
+ private static final int INTERPRETER_FRAME_METHOD_OFFSET = INTERPRETER_FRAME_LAST_SP_OFFSET - 1;
+ private static int INTERPRETER_FRAME_MDX_OFFSET; // Non-core builds only
+ private static int INTERPRETER_FRAME_CACHE_OFFSET;
+ private static int INTERPRETER_FRAME_LOCALS_OFFSET;
+ private static int INTERPRETER_FRAME_BCX_OFFSET;
+ private static int INTERPRETER_FRAME_INITIAL_SP_OFFSET;
+ private static int INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET;
+ private static int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET;
+
+ // Entry frames
+ private static int ENTRY_FRAME_CALL_WRAPPER_OFFSET = -8;
+
+ // Native frames
+ private static final int NATIVE_FRAME_INITIAL_PARAM_OFFSET = 2;
+
+ private static VMReg fp = new VMReg(29);
+
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ private static synchronized void initialize(TypeDataBase db) {
+ INTERPRETER_FRAME_MDX_OFFSET = INTERPRETER_FRAME_METHOD_OFFSET - 1;
+ INTERPRETER_FRAME_CACHE_OFFSET = INTERPRETER_FRAME_MDX_OFFSET - 1;
+ INTERPRETER_FRAME_LOCALS_OFFSET = INTERPRETER_FRAME_CACHE_OFFSET - 1;
+ INTERPRETER_FRAME_BCX_OFFSET = INTERPRETER_FRAME_LOCALS_OFFSET - 1;
+ INTERPRETER_FRAME_INITIAL_SP_OFFSET = INTERPRETER_FRAME_BCX_OFFSET - 1;
+ INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
+ INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
+ }
+
+
+ // an additional field beyond sp and pc:
+ Address raw_fp; // frame pointer
+ private Address raw_unextendedSP;
+
+ private AARCH64Frame() {
+ }
+
+ private void adjustForDeopt() {
+ if ( pc != null) {
+ // Look for a deopt pc and if it is deopted convert to original pc
+ CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc);
+ if (cb != null && cb.isJavaMethod()) {
+ NMethod nm = (NMethod) cb;
+ if (pc.equals(nm.deoptHandlerBegin())) {
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(this.getUnextendedSP() != null, "null SP in Java frame");
+ }
+ // adjust pc if frame is deoptimized.
+ pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset());
+ deoptimized = true;
+ }
+ }
+ }
+ }
+
+ public AARCH64Frame(Address raw_sp, Address raw_fp, Address pc) {
+ this.raw_sp = raw_sp;
+ this.raw_unextendedSP = raw_sp;
+ this.raw_fp = raw_fp;
+ this.pc = pc;
+ adjustUnextendedSP();
+
+ // Frame must be fully constructed before this call
+ adjustForDeopt();
+
+ if (DEBUG) {
+ System.out.println("AARCH64Frame(sp, fp, pc): " + this);
+ dumpStack();
+ }
+ }
+
+ public AARCH64Frame(Address raw_sp, Address raw_fp) {
+ this.raw_sp = raw_sp;
+ this.raw_unextendedSP = raw_sp;
+ this.raw_fp = raw_fp;
+ this.pc = raw_sp.getAddressAt(-1 * VM.getVM().getAddressSize());
+ adjustUnextendedSP();
+
+ // Frame must be fully constructed before this call
+ adjustForDeopt();
+
+ if (DEBUG) {
+ System.out.println("AARCH64Frame(sp, fp): " + this);
+ dumpStack();
+ }
+ }
+
+ public AARCH64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) {
+ this.raw_sp = raw_sp;
+ this.raw_unextendedSP = raw_unextendedSp;
+ this.raw_fp = raw_fp;
+ this.pc = pc;
+ adjustUnextendedSP();
+
+ // Frame must be fully constructed before this call
+ adjustForDeopt();
+
+ if (DEBUG) {
+ System.out.println("AARCH64Frame(sp, unextendedSP, fp, pc): " + this);
+ dumpStack();
+ }
+
+ }
+
+ public Object clone() {
+ AARCH64Frame frame = new AARCH64Frame();
+ frame.raw_sp = raw_sp;
+ frame.raw_unextendedSP = raw_unextendedSP;
+ frame.raw_fp = raw_fp;
+ frame.pc = pc;
+ frame.deoptimized = deoptimized;
+ return frame;
+ }
+
+ public boolean equals(Object arg) {
+ if (arg == null) {
+ return false;
+ }
+
+ if (!(arg instanceof AARCH64Frame)) {
+ return false;
+ }
+
+ AARCH64Frame other = (AARCH64Frame) arg;
+
+ return (AddressOps.equal(getSP(), other.getSP()) &&
+ AddressOps.equal(getUnextendedSP(), other.getUnextendedSP()) &&
+ AddressOps.equal(getFP(), other.getFP()) &&
+ AddressOps.equal(getPC(), other.getPC()));
+ }
+
+ public int hashCode() {
+ if (raw_sp == null) {
+ return 0;
+ }
+
+ return raw_sp.hashCode();
+ }
+
+ public String toString() {
+ return "sp: " + (getSP() == null? "null" : getSP().toString()) +
+ ", unextendedSP: " + (getUnextendedSP() == null? "null" : getUnextendedSP().toString()) +
+ ", fp: " + (getFP() == null? "null" : getFP().toString()) +
+ ", pc: " + (pc == null? "null" : pc.toString());
+ }
+
+ // accessors for the instance variables
+ public Address getFP() { return raw_fp; }
+ public Address getSP() { return raw_sp; }
+ public Address getID() { return raw_sp; }
+
+ // FIXME: not implemented yet
+ public boolean isSignalHandlerFrameDbg() { return false; }
+ public int getSignalNumberDbg() { return 0; }
+ public String getSignalNameDbg() { return null; }
+
+ public boolean isInterpretedFrameValid() {
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(isInterpretedFrame(), "Not an interpreted frame");
+ }
+
+ // These are reasonable sanity checks
+ if (getFP() == null || getFP().andWithMask(0x3) != null) {
+ return false;
+ }
+
+ if (getSP() == null || getSP().andWithMask(0x3) != null) {
+ return false;
+ }
+
+ if (getFP().addOffsetTo(INTERPRETER_FRAME_INITIAL_SP_OFFSET * VM.getVM().getAddressSize()).lessThan(getSP())) {
+ return false;
+ }
+
+ // These are hacks to keep us out of trouble.
+ // The problem with these is that they mask other problems
+ if (getFP().lessThanOrEqual(getSP())) {
+ // this attempts to deal with unsigned comparison above
+ return false;
+ }
+
+ if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) {
+ // stack frames shouldn't be large.
+ return false;
+ }
+
+ return true;
+ }
+
+ // FIXME: not applicable in current system
+ // void patch_pc(Thread* thread, address pc);
+
+ public Frame sender(RegisterMap regMap, CodeBlob cb) {
+ AARCH64RegisterMap map = (AARCH64RegisterMap) regMap;
+
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(map != null, "map must be set");
+ }
+
+ // Default is we done have to follow them. The sender_for_xxx will
+ // update it accordingly
+ map.setIncludeArgumentOops(false);
+
+ if (isEntryFrame()) return senderForEntryFrame(map);
+ if (isInterpretedFrame()) return senderForInterpreterFrame(map);
+
+ if(cb == null) {
+ cb = VM.getVM().getCodeCache().findBlob(getPC());
+ } else {
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same");
+ }
+ }
+
+ if (cb != null) {
+ return senderForCompiledFrame(map, cb);
+ }
+
+ // Must be native-compiled frame, i.e. the marshaling code for native
+ // methods that exists in the core system.
+ return new AARCH64Frame(getSenderSP(), getLink(), getSenderPC());
+ }
+
+ private Frame senderForEntryFrame(AARCH64RegisterMap map) {
+ if (DEBUG) {
+ System.out.println("senderForEntryFrame");
+ }
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(map != null, "map must be set");
+ }
+ // Java frame called from C; skip all C frames and return top C
+ // frame of that chunk as the sender
+ AARCH64JavaCallWrapper jcw = (AARCH64JavaCallWrapper) getEntryFrameCallWrapper();
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero");
+ Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack");
+ }
+ AARCH64Frame fr;
+ if (jcw.getLastJavaPC() != null) {
+ fr = new AARCH64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC());
+ } else {
+ fr = new AARCH64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP());
+ }
+ map.clear();
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(map.getIncludeArgumentOops(), "should be set by clear");
+ }
+ return fr;
+ }
+
+ //------------------------------------------------------------------------------
+ // frame::adjust_unextended_sp
+ private void adjustUnextendedSP() {
+ // If we are returning to a compiled MethodHandle call site, the
+ // saved_fp will in fact be a saved value of the unextended SP. The
+ // simplest way to tell whether we are returning to such a call site
+ // is as follows:
+
+ CodeBlob cb = cb();
+ NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull();
+ if (senderNm != null) {
+ // If the sender PC is a deoptimization point, get the original
+ // PC. For MethodHandle call site the unextended_sp is stored in
+ // saved_fp.
+ if (senderNm.isDeoptMhEntry(getPC())) {
+ // DEBUG_ONLY(verifyDeoptMhOriginalPc(senderNm, getFP()));
+ raw_unextendedSP = getFP();
+ }
+ else if (senderNm.isDeoptEntry(getPC())) {
+ // DEBUG_ONLY(verifyDeoptOriginalPc(senderNm, raw_unextendedSp));
+ }
+ else if (senderNm.isMethodHandleReturn(getPC())) {
+ raw_unextendedSP = getFP();
+ }
+ }
+ }
+
+ private Frame senderForInterpreterFrame(AARCH64RegisterMap map) {
+ if (DEBUG) {
+ System.out.println("senderForInterpreterFrame");
+ }
+ Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
+ Address sp = addressOfStackSlot(SENDER_SP_OFFSET);
+ // We do not need to update the callee-save register mapping because above
+ // us is either another interpreter frame or a converter-frame, but never
+ // directly a compiled frame.
+ // 11/24/04 SFG. With the removal of adapter frames this is no longer true.
+ // However c2 no longer uses callee save register for java calls so there
+ // are no callee register to find.
+
+ if (map.getUpdateMap())
+ updateMapWithSavedLink(map, addressOfStackSlot(LINK_OFFSET));
+
+ return new AARCH64Frame(sp, unextendedSP, getLink(), getSenderPC());
+ }
+
+ private void updateMapWithSavedLink(RegisterMap map, Address savedFPAddr) {
+ map.setLocation(fp, savedFPAddr);
+ }
+
+ private Frame senderForCompiledFrame(AARCH64RegisterMap map, CodeBlob cb) {
+ if (DEBUG) {
+ System.out.println("senderForCompiledFrame");
+ }
+
+ //
+ // NOTE: some of this code is (unfortunately) duplicated AARCH64CurrentFrameGuess
+ //
+
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(map != null, "map must be set");
+ }
+
+ // frame owned by optimizing compiler
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(cb.getFrameSize() >= 0, "must have non-zero frame size");
+ }
+ Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize());
+
+ // The return_address is always the word on the stack
+ Address senderPC = senderSP.getAddressAt(-1 * VM.getVM().getAddressSize());
+
+ // This is the saved value of FP which may or may not really be an FP.
+ // It is only an FP if the sender is an interpreter frame.
+ Address savedFPAddr = senderSP.addOffsetTo(- SENDER_SP_OFFSET * VM.getVM().getAddressSize());
+
+ if (map.getUpdateMap()) {
+ // Tell GC to use argument oopmaps for some runtime stubs that need it.
+ // For C1, the runtime stub might not have oop maps, so set this flag
+ // outside of update_register_map.
+ map.setIncludeArgumentOops(cb.callerMustGCArguments());
+
+ if (cb.getOopMaps() != null) {
+ ImmutableOopMapSet.updateRegisterMap(this, cb, map, true);
+ }
+
+ // Since the prolog does the save and restore of FP there is no oopmap
+ // for it so we must fill in its location as if there was an oopmap entry
+ // since if our caller was compiled code there could be live jvm state in it.
+ updateMapWithSavedLink(map, savedFPAddr);
+ }
+
+ return new AARCH64Frame(senderSP, savedFPAddr.getAddressAt(0), senderPC);
+ }
+
+ protected boolean hasSenderPD() {
+ return true;
+ }
+
+ public long frameSize() {
+ return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize());
+ }
+
+ public Address getLink() {
+ try {
+ if (DEBUG) {
+ System.out.println("Reading link at " + addressOfStackSlot(LINK_OFFSET)
+ + " = " + addressOfStackSlot(LINK_OFFSET).getAddressAt(0));
+ }
+ return addressOfStackSlot(LINK_OFFSET).getAddressAt(0);
+ } catch (Exception e) {
+ if (DEBUG)
+ System.out.println("Returning null");
+ return null;
+ }
+ }
+
+ // FIXME: not implementable yet
+ //inline void frame::set_link(intptr_t* addr) { *(intptr_t **)addr_at(link_offset) = addr; }
+
+ public Address getUnextendedSP() { return raw_unextendedSP; }
+
+ // Return address:
+ public Address getSenderPCAddr() { return addressOfStackSlot(RETURN_ADDR_OFFSET); }
+ public Address getSenderPC() { return getSenderPCAddr().getAddressAt(0); }
+
+ // return address of param, zero origin index.
+ public Address getNativeParamAddr(int idx) {
+ return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx);
+ }
+
+ public Address getSenderSP() { return addressOfStackSlot(SENDER_SP_OFFSET); }
+
+ public Address addressOfInterpreterFrameLocals() {
+ return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET);
+ }
+
+ private Address addressOfInterpreterFrameBCX() {
+ return addressOfStackSlot(INTERPRETER_FRAME_BCX_OFFSET);
+ }
+
+ public int getInterpreterFrameBCI() {
+ // FIXME: this is not atomic with respect to GC and is unsuitable
+ // for use in a non-debugging, or reflective, system. Need to
+ // figure out how to express this.
+ Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0);
+ Address methodHandle = addressOfInterpreterFrameMethod().getAddressAt(0);
+ Method method = (Method)Metadata.instantiateWrapperFor(methodHandle);
+ return bcpToBci(bcp, method);
+ }
+
+ public Address addressOfInterpreterFrameMDX() {
+ return addressOfStackSlot(INTERPRETER_FRAME_MDX_OFFSET);
+ }
+
+ // FIXME
+ //inline int frame::interpreter_frame_monitor_size() {
+ // return BasicObjectLock::size();
+ //}
+
+ // expression stack
+ // (the max_stack arguments are used by the GC; see class FrameClosure)
+
+ public Address addressOfInterpreterFrameExpressionStack() {
+ Address monitorEnd = interpreterFrameMonitorEnd().address();
+ return monitorEnd.addOffsetTo(-1 * VM.getVM().getAddressSize());
+ }
+
+ public int getInterpreterFrameExpressionStackDirection() { return -1; }
+
+ // top of expression stack
+ public Address addressOfInterpreterFrameTOS() {
+ return getSP();
+ }
+
+ /** Expression stack from top down */
+ public Address addressOfInterpreterFrameTOSAt(int slot) {
+ return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize());
+ }
+
+ public Address getInterpreterFrameSenderSP() {
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(isInterpretedFrame(), "interpreted frame expected");
+ }
+ return addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
+ }
+
+ // Monitors
+ public BasicObjectLock interpreterFrameMonitorBegin() {
+ return new BasicObjectLock(addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET));
+ }
+
+ public BasicObjectLock interpreterFrameMonitorEnd() {
+ Address result = addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET).getAddressAt(0);
+ if (Assert.ASSERTS_ENABLED) {
+ // make sure the pointer points inside the frame
+ Assert.that(AddressOps.gt(getFP(), result), "result must < than frame pointer");
+ Assert.that(AddressOps.lte(getSP(), result), "result must >= than stack pointer");
+ }
+ return new BasicObjectLock(result);
+ }
+
+ public int interpreterFrameMonitorSize() {
+ return BasicObjectLock.size();
+ }
+
+ // Method
+ public Address addressOfInterpreterFrameMethod() {
+ return addressOfStackSlot(INTERPRETER_FRAME_METHOD_OFFSET);
+ }
+
+ // Constant pool cache
+ public Address addressOfInterpreterFrameCPCache() {
+ return addressOfStackSlot(INTERPRETER_FRAME_CACHE_OFFSET);
+ }
+
+ // Entry frames
+ public JavaCallWrapper getEntryFrameCallWrapper() {
+ return new AARCH64JavaCallWrapper(addressOfStackSlot(ENTRY_FRAME_CALL_WRAPPER_OFFSET).getAddressAt(0));
+ }
+
+ protected Address addressOfSavedOopResult() {
+ // offset is 2 for compiler2 and 3 for compiler1
+ return getSP().addOffsetTo((VM.getVM().isClientCompiler() ? 2 : 3) *
+ VM.getVM().getAddressSize());
+ }
+
+ protected Address addressOfSavedReceiver() {
+ return getSP().addOffsetTo(-4 * VM.getVM().getAddressSize());
+ }
+
+ private void dumpStack() {
+ for (Address addr = getSP().addOffsetTo(-4 * VM.getVM().getAddressSize());
+ AddressOps.lt(addr, getSP());
+ addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
+ System.out.println(addr + ": " + addr.getAddressAt(0));
+ }
+ System.out.println("-----------------------");
+ for (Address addr = getSP();
+ AddressOps.lte(addr, getSP().addOffsetTo(20 * VM.getVM().getAddressSize()));
+ addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
+ System.out.println(addr + ": " + addr.getAddressAt(0));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64JavaCallWrapper.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.runtime.aarch64;
+
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.runtime.*;
+
+public class AARCH64JavaCallWrapper extends JavaCallWrapper {
+ private static AddressField lastJavaFPField;
+
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ private static synchronized void initialize(TypeDataBase db) {
+ Type type = db.lookupType("JavaFrameAnchor");
+
+ lastJavaFPField = type.getAddressField("_last_Java_fp");
+ }
+
+ public AARCH64JavaCallWrapper(Address addr) {
+ super(addr);
+ }
+
+ public Address getLastJavaFP() {
+ return lastJavaFPField.getValue(addr.addOffsetTo(anchorField.getOffset()));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/aarch64/AARCH64RegisterMap.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.runtime.aarch64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.runtime.*;
+
+public class AARCH64RegisterMap extends RegisterMap {
+
+ /** This is the only public constructor */
+ public AARCH64RegisterMap(JavaThread thread, boolean updateMap) {
+ super(thread, updateMap);
+ }
+
+ protected AARCH64RegisterMap(RegisterMap map) {
+ super(map);
+ }
+
+ public Object clone() {
+ AARCH64RegisterMap retval = new AARCH64RegisterMap(this);
+ return retval;
+ }
+
+ // no PD state to clear or copy:
+ protected void clearPD() {}
+ protected void initializePD() {}
+ protected void initializeFromPD(RegisterMap map) {}
+ protected Address getLocationPD(VMReg reg) { return null; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_aarch64/LinuxAARCH64JavaThreadPDAccess.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc.
+ * 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.runtime.linux_aarch64;
+
+import java.io.*;
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.aarch64.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class LinuxAARCH64JavaThreadPDAccess implements JavaThreadPDAccess {
+ private static AddressField lastJavaFPField;
+ private static AddressField osThreadField;
+
+ // Field from OSThread
+ private static CIntegerField osThreadThreadIDField;
+
+ // This is currently unneeded but is being kept in case we change
+ // the currentFrameGuess algorithm
+ private static final long GUESS_SCAN_RANGE = 128 * 1024;
+
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ private static synchronized void initialize(TypeDataBase db) {
+ Type type = db.lookupType("JavaThread");
+ osThreadField = type.getAddressField("_osthread");
+
+ Type anchorType = db.lookupType("JavaFrameAnchor");
+ lastJavaFPField = anchorType.getAddressField("_last_Java_fp");
+
+ Type osThreadType = db.lookupType("OSThread");
+ osThreadThreadIDField = osThreadType.getCIntegerField("_thread_id");
+ }
+
+ public Address getLastJavaFP(Address addr) {
+ return lastJavaFPField.getValue(addr.addOffsetTo(sun.jvm.hotspot.runtime.JavaThread.getAnchorField().getOffset()));
+ }
+
+ public Address getLastJavaPC(Address addr) {
+ return null;
+ }
+
+ public Address getBaseOfStackPointer(Address addr) {
+ return null;
+ }
+
+ public Frame getLastFramePD(JavaThread thread, Address addr) {
+ Address fp = thread.getLastJavaFP();
+ if (fp == null) {
+ return null; // no information
+ }
+ return new AARCH64Frame(thread.getLastJavaSP(), fp);
+ }
+
+ public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) {
+ return new AARCH64RegisterMap(thread, updateMap);
+ }
+
+ public Frame getCurrentFrameGuess(JavaThread thread, Address addr) {
+ ThreadProxy t = getThreadProxy(addr);
+ AARCH64ThreadContext context = (AARCH64ThreadContext) t.getContext();
+ AARCH64CurrentFrameGuess guesser = new AARCH64CurrentFrameGuess(context, thread);
+ if (!guesser.run(GUESS_SCAN_RANGE)) {
+ return null;
+ }
+ if (guesser.getPC() == null) {
+ return new AARCH64Frame(guesser.getSP(), guesser.getFP());
+ } else {
+ return new AARCH64Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
+ }
+ }
+
+ public void printThreadIDOn(Address addr, PrintStream tty) {
+ tty.print(getThreadProxy(addr));
+ }
+
+ public void printInfoOn(Address threadAddr, PrintStream tty) {
+ tty.print("Thread id: ");
+ printThreadIDOn(threadAddr, tty);
+// tty.println("\nPostJavaState: " + getPostJavaState(threadAddr));
+ }
+
+ public Address getLastSP(Address addr) {
+ ThreadProxy t = getThreadProxy(addr);
+ AARCH64ThreadContext context = (AARCH64ThreadContext) t.getContext();
+ return context.getRegisterAsAddress(AARCH64ThreadContext.SP);
+ }
+
+ public ThreadProxy getThreadProxy(Address addr) {
+ // Addr is the address of the JavaThread.
+ // Fetch the OSThread (for now and for simplicity, not making a
+ // separate "OSThread" class in this package)
+ Address osThreadAddr = osThreadField.getValue(addr);
+ // Get the address of the _thread_id from the OSThread
+ Address threadIdAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset());
+
+ JVMDebugger debugger = VM.getVM().getDebugger();
+ return debugger.getThreadForIdentifierAddress(threadIdAddr);
+ }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/AltPlatformInfo.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/AltPlatformInfo.java Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,10 @@
package sun.jvm.hotspot.utilities;
public interface AltPlatformInfo {
+
// Additional cpu types can be tested via this interface
+ public boolean knownCPU(String cpu);
- public boolean knownCPU(String cpu);
-}
\ No newline at end of file
+ // Mangle a cpu name if necessary
+ public String getCPU(String cpu);
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -52,27 +52,54 @@
}
}
- /* Returns "sparc" for SPARC based platforms and "x86" for x86 based
- platforms. Otherwise returns the value of os.arch. If the value
- is not recognized as supported, an exception is thrown instead. */
+ public static boolean knownCPU(String cpu) {
+ final String[] KNOWN =
+ new String[] {"i386", "x86", "x86_64", "amd64", "sparc", "sparcv9", "ppc64", "aarch64"};
+
+ for(String s : KNOWN) {
+ if(s.equals(cpu))
+ return true;
+ }
+
+ return false;
+ }
+
+ /* Returns "sparc" for SPARC based platforms "x86" for x86 based
+ platforms and x86_64 for 64bit x86 based platform. Otherwise
+ returns the value of os.arch. If the value is not recognized as supported,
+ an exception is thrown instead. */
+
public static String getCPU() throws UnsupportedPlatformException {
String cpu = System.getProperty("os.arch");
- if (cpu.equals("i386") || cpu.equals("x86")) {
+
+ // Let any additional CPU mangling fire first
+ try {
+ Class pic = Class.forName("sun.jvm.hotspot.utilities.PlatformInfoClosed");
+ AltPlatformInfo api = (AltPlatformInfo) pic.newInstance();
+ if (api.knownCPU(cpu)) {
+ return api.getCPU(cpu);
+ }
+ } catch (Exception e) {
+ // Ignored
+ }
+
+ // Check that CPU is supported
+ if (!knownCPU(cpu)) {
+ throw new UnsupportedPlatformException("CPU type " + cpu + " not yet supported");
+ }
+
+ // Tweeks
+ if (cpu.equals("i386"))
return "x86";
- } else if (cpu.equals("sparc") || cpu.equals("sparcv9")) {
+
+ if (cpu.equals("sparcv9"))
return "sparc";
- } else if (cpu.equals("ia64") || cpu.equals("amd64") || cpu.equals("x86_64") || cpu.equals("ppc64") || cpu.equals("aarch64")) {
- return cpu;
- } else {
- try {
- Class pic = Class.forName("sun.jvm.hotspot.utilities.PlatformInfoClosed");
- AltPlatformInfo api = (AltPlatformInfo)pic.newInstance();
- if (api.knownCPU(cpu)) {
- return cpu;
- }
- } catch (Exception e) {}
- throw new UnsupportedPlatformException("CPU type " + cpu + " not yet supported");
- }
+
+ if (cpu.equals("x86_64"))
+ return "amd64";
+
+ return cpu;
+
}
// this main is invoked from Makefile to make platform specific agent Makefile(s).
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java Thu Jun 25 09:48:50 2015 -0700
@@ -84,11 +84,11 @@
}
public boolean isInNewGen() {
- return ((gen != null) && (gen.level() == 0));
+ return ((gen != null) && (gen == ((GenCollectedHeap)heap).getGen(0)));
}
public boolean isInOldGen() {
- return ((gen != null) && (gen.level() == 1));
+ return ((gen != null) && (gen == ((GenCollectedHeap)heap).getGen(1)));
}
public boolean inOtherGen() {
@@ -207,8 +207,6 @@
tty.print("In new generation ");
} else if (isInOldGen()) {
tty.print("In old generation ");
- } else if (gen != null) {
- tty.print("In Generation " + getGeneration().level());
} else {
tty.print("In unknown section of Java heap");
}
--- a/hotspot/make/bsd/makefiles/dtrace.make Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/make/bsd/makefiles/dtrace.make Thu Jun 25 09:48:50 2015 -0700
@@ -263,14 +263,19 @@
$(DtraceOutDir):
mkdir $(DtraceOutDir)
+# When building using a devkit, dtrace cannot find the correct preprocessor so
+# we run it explicitly before runing dtrace.
$(DtraceOutDir)/hotspot.h: $(DTRACE_COMMON_SRCDIR)/hotspot.d | $(DtraceOutDir)
- $(QUIETLY) $(DTRACE_PROG) $(DTRACE_OPTS) -C -I. -h -o $@ -s $(DTRACE_COMMON_SRCDIR)/hotspot.d
+ $(QUIETLY) $(CC) -E $(DTRACE_OPTS) -I. -x c $(DTRACE_COMMON_SRCDIR)/hotspot.d > $(DtraceOutDir)/hotspot.d
+ $(QUIETLY) $(DTRACE_PROG) -h -o $@ -s $(DtraceOutDir)/hotspot.d
$(DtraceOutDir)/hotspot_jni.h: $(DTRACE_COMMON_SRCDIR)/hotspot_jni.d | $(DtraceOutDir)
- $(QUIETLY) $(DTRACE_PROG) $(DTRACE_OPTS) -C -I. -h -o $@ -s $(DTRACE_COMMON_SRCDIR)/hotspot_jni.d
+ $(QUIETLY) $(CC) -E $(DTRACE_OPTS) -I. -x c $(DTRACE_COMMON_SRCDIR)/hotspot_jni.d > $(DtraceOutDir)/hotspot_jni.d
+ $(QUIETLY) $(DTRACE_PROG) -h -o $@ -s $(DtraceOutDir)/hotspot_jni.d
$(DtraceOutDir)/hs_private.h: $(DTRACE_COMMON_SRCDIR)/hs_private.d | $(DtraceOutDir)
- $(QUIETLY) $(DTRACE_PROG) $(DTRACE_OPTS) -C -I. -h -o $@ -s $(DTRACE_COMMON_SRCDIR)/hs_private.d
+ $(QUIETLY) $(CC) -E $(DTRACE_OPTS) -I. -x c $(DTRACE_COMMON_SRCDIR)/hs_private.d > $(DtraceOutDir)/hs_private.d
+ $(QUIETLY) $(DTRACE_PROG) -h -o $@ -s $(DtraceOutDir)/hs_private.d
dtrace_gen_headers: $(DtraceOutDir)/hotspot.h $(DtraceOutDir)/hotspot_jni.h $(DtraceOutDir)/hs_private.h
--- a/hotspot/make/bsd/makefiles/universal.gmk Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/make/bsd/makefiles/universal.gmk Thu Jun 25 09:48:50 2015 -0700
@@ -56,13 +56,14 @@
universalize: $(UNIVERSAL_LIPO_LIST) $(UNIVERSAL_COPY_LIST)
$(RM) -r $(EXPORT_PATH)/lib/{i386,amd64}
+LIPO ?= lipo
# Package built libraries in a universal binary
$(UNIVERSAL_LIPO_LIST):
BUILT_LIPO_FILES="`find $(EXPORT_LIB_DIR)/{i386,amd64}/$(subst $(EXPORT_LIB_DIR)/,,$@) 2>/dev/null`" || test $$? = "1"; \
if [ -n "$${BUILT_LIPO_FILES}" ]; then \
$(MKDIR) -p $(shell dirname $@); \
- lipo -create -output $@ $${BUILT_LIPO_FILES}; \
+ $(LIPO) -create -output $@ $${BUILT_LIPO_FILES}; \
fi
--- a/hotspot/make/sa.files Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/make/sa.files Thu Jun 25 09:48:50 2015 -0700
@@ -44,6 +44,7 @@
$(AGENT_SRC_DIR)/sun/jvm/hotspot/compiler/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/aarch64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/amd64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/bsd/x86/*.java \
@@ -55,6 +56,7 @@
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/amd64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ia64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ppc64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/aarch64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/x86/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/sparc/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/posix/*.java \
@@ -63,6 +65,7 @@
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/amd64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/ppc64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/aarch64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/sparc/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/x86/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/*.java \
@@ -70,6 +73,7 @@
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/ppc64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/sparc/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/x86/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/aarch64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/sparc/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/win32/coff/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/windbg/*.java \
@@ -92,11 +96,13 @@
$(AGENT_SRC_DIR)/sun/jvm/hotspot/prims/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/aarch64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/bsd/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/bsd_amd64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/bsd_x86/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_aarch64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_x86/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_sparc/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_ppc64/*.java \
--- a/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/aarch64/vm/frame_aarch64.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -526,16 +526,6 @@
return frame(sender_sp(), link(), sender_pc());
}
-bool frame::interpreter_frame_equals_unpacked_fp(intptr_t* fp) {
- assert(is_interpreted_frame(), "must be interpreter frame");
- Method* method = interpreter_frame_method();
- // When unpacking an optimized frame the frame pointer is
- // adjusted with:
- int diff = (method->max_locals() - method->size_of_parameters()) *
- Interpreter::stackElementWords;
- return _fp == (fp - diff);
-}
-
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
// QQQ
#ifdef CC_INTERP
--- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, Red Hat Inc. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -84,7 +84,7 @@
#ifdef BUILTIN_SIM
#define UseBuiltinSim true
-#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
+#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
\
product(bool, NotifySimulator, UseBuiltinSim, \
"tell the AArch64 sim where we are in method code") \
@@ -112,7 +112,7 @@
#define NotifySimulator false
#define UseSimulatorCache false
#define DisableBCCheck true
-#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
+#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
\
product(bool, NearCpool, true, \
"constant pool is close to instructions") \
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -2888,41 +2888,40 @@
cmp(src1, rscratch1);
}
-void MacroAssembler::store_check(Register obj) {
- // Does a store check for the oop in register obj. The content of
- // register obj is destroyed afterwards.
- store_check_part_1(obj);
- store_check_part_2(obj);
-}
-
void MacroAssembler::store_check(Register obj, Address dst) {
store_check(obj);
}
-
-// split the store check operation so that other instructions can be scheduled inbetween
-void MacroAssembler::store_check_part_1(Register obj) {
- BarrierSet* bs = Universe::heap()->barrier_set();
- assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind");
- lsr(obj, obj, CardTableModRefBS::card_shift);
-}
-
-void MacroAssembler::store_check_part_2(Register obj) {
+void MacroAssembler::store_check(Register obj) {
+ // Does a store check for the oop in register obj. The content of
+ // register obj is destroyed afterwards.
+
BarrierSet* bs = Universe::heap()->barrier_set();
assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind");
- CardTableModRefBS* ct = (CardTableModRefBS*)bs;
+
+ CardTableModRefBS* ct = barrier_set_cast<CardTableModRefBS>(bs);
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
- // The calculation for byte_map_base is as follows:
- // byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
- // So this essentially converts an address to a displacement and
- // it will never need to be relocated.
-
- // FIXME: It's not likely that disp will fit into an offset so we
- // don't bother to check, but it could save an instruction.
- intptr_t disp = (intptr_t) ct->byte_map_base;
- mov(rscratch1, disp);
- strb(zr, Address(obj, rscratch1));
+ lsr(obj, obj, CardTableModRefBS::card_shift);
+
+ assert(CardTableModRefBS::dirty_card_val() == 0, "must be");
+
+ {
+ ExternalAddress cardtable((address) ct->byte_map_base);
+ unsigned long offset;
+ adrp(rscratch1, cardtable, offset);
+ assert(offset == 0, "byte_map_base is misaligned");
+ }
+
+ if (UseCondCardMark) {
+ Label L_already_dirty;
+ ldrb(rscratch2, Address(obj, rscratch1));
+ cbz(rscratch2, L_already_dirty);
+ strb(zr, Address(obj, rscratch1));
+ bind(L_already_dirty);
+ } else {
+ strb(zr, Address(obj, rscratch1));
+ }
}
void MacroAssembler::load_klass(Register dst, Register src) {
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -756,10 +756,6 @@
#endif // INCLUDE_ALL_GCS
- // split store_check(Register obj) to enhance instruction interleaving
- void store_check_part_1(Register obj);
- void store_check_part_2(Register obj);
-
// oop manipulations
void load_klass(Register dst, Register src);
void store_klass(Register dst, Register src);
--- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -63,7 +63,7 @@
define_pd_global(uintx, TypeProfileLevel, 111);
// Platform dependent flag handling: flags only defined on this platform.
-#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
+#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
\
/* Load poll address from thread. This is used to implement per-thread */ \
/* safepoints on platforms != IA64. */ \
--- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -510,7 +510,8 @@
void VM_Version::determine_features() {
#if defined(ABI_ELFv2)
- const int code_size = (num_features+1+2*7)*BytesPerInstWord; // TODO(asmundak): calculation is incorrect.
+ // 1 InstWord per call for the blr instruction.
+ const int code_size = (num_features+1+2*1)*BytesPerInstWord;
#else
// 7 InstWords for each call (function descriptor + blr instruction).
const int code_size = (num_features+1+2*7)*BytesPerInstWord;
@@ -545,7 +546,8 @@
a->popcntw(R7, R5); // code[6] -> popcntw
a->fcfids(F3, F4); // code[7] -> fcfids
a->vand(VR0, VR0, VR0); // code[8] -> vand
- a->lqarx_unchecked(R7, R3_ARG1, R4_ARG2, 1); // code[9] -> lqarx_m
+ // arg0 of lqarx must be an even register, (arg1 + arg2) must be a multiple of 16
+ a->lqarx_unchecked(R6, R3_ARG1, R4_ARG2, 1); // code[9] -> lqarx_m
a->vcipher(VR0, VR1, VR2); // code[10] -> vcipher
a->vpmsumb(VR0, VR1, VR2); // code[11] -> vpmsumb
a->tcheck(0); // code[12] -> tcheck
@@ -577,7 +579,8 @@
// Execute code. Illegal instructions will be replaced by 0 in the signal handler.
VM_Version::_is_determine_features_test_running = true;
- (*test)((address)mid_of_test_area, (uint64_t)0);
+ // We must align the first argument to 16 bytes because of the lqarx check.
+ (*test)((address)align_size_up((intptr_t)mid_of_test_area, 16), (uint64_t)0);
VM_Version::_is_determine_features_test_running = false;
// determine which instructions are legal.
@@ -619,12 +622,12 @@
MacroAssembler* a = new MacroAssembler(&cb);
// Emit code.
- uint64_t (*get_dscr)() = (uint64_t(*)())(void *)a->emit_fd();
+ uint64_t (*get_dscr)() = (uint64_t(*)())(void *)a->function_entry();
uint32_t *code = (uint32_t *)a->pc();
a->mfdscr(R3);
a->blr();
- void (*set_dscr)(long) = (void(*)(long))(void *)a->emit_fd();
+ void (*set_dscr)(long) = (void(*)(long))(void *)a->function_entry();
a->mtdscr(R3);
a->blr();
--- a/hotspot/src/cpu/sparc/vm/frame_sparc.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/sparc/vm/frame_sparc.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -599,12 +599,6 @@
return next_younger_sp_or_null(valid_sp, sp) != NULL;
}
-
-bool frame::interpreter_frame_equals_unpacked_fp(intptr_t* fp) {
- assert(is_interpreted_frame(), "must be interpreter frame");
- return this->fp() == fp;
-}
-
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
#ifdef CC_INTERP
// Is there anything to do?
--- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -81,7 +81,7 @@
define_pd_global(uintx, TypeProfileLevel, 111);
-#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
+#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
\
product(intx, UseVIS, 99, \
"Highest supported VIS instructions set on Sparc") \
--- a/hotspot/src/cpu/x86/vm/frame_x86.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/x86/vm/frame_x86.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -524,17 +524,6 @@
return frame(sender_sp(), link(), sender_pc());
}
-
-bool frame::interpreter_frame_equals_unpacked_fp(intptr_t* fp) {
- assert(is_interpreted_frame(), "must be interpreter frame");
- Method* method = interpreter_frame_method();
- // When unpacking an optimized frame the frame pointer is
- // adjusted with:
- int diff = (method->max_locals() - method->size_of_parameters()) *
- Interpreter::stackElementWords;
- return _fp == (fp - diff);
-}
-
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
// QQQ
#ifdef CC_INTERP
--- a/hotspot/src/cpu/x86/vm/globals_x86.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/x86/vm/globals_x86.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -84,7 +84,7 @@
define_pd_global(bool, PreserveFramePointer, false);
-#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
+#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
\
develop(bool, IEEEPrecision, true, \
"Enables IEEE precision (for INTEL only)") \
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -4260,31 +4260,24 @@
//////////////////////////////////////////////////////////////////////////////////
+void MacroAssembler::store_check(Register obj, Address dst) {
+ store_check(obj);
+}
+
void MacroAssembler::store_check(Register obj) {
// Does a store check for the oop in register obj. The content of
// register obj is destroyed afterwards.
- store_check_part_1(obj);
- store_check_part_2(obj);
-}
-
-void MacroAssembler::store_check(Register obj, Address dst) {
- store_check(obj);
-}
-
-
-// split the store check operation so that other instructions can be scheduled inbetween
-void MacroAssembler::store_check_part_1(Register obj) {
+
BarrierSet* bs = Universe::heap()->barrier_set();
assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind");
- shrptr(obj, CardTableModRefBS::card_shift);
-}
-
-void MacroAssembler::store_check_part_2(Register obj) {
- BarrierSet* bs = Universe::heap()->barrier_set();
- assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind");
+
CardTableModRefBS* ct = barrier_set_cast<CardTableModRefBS>(bs);
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
+ shrptr(obj, CardTableModRefBS::card_shift);
+
+ Address card_addr;
+
// The calculation for byte_map_base is as follows:
// byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
// So this essentially converts an address to a displacement and it will
@@ -4292,8 +4285,7 @@
// large for a 32bit displacement.
intptr_t disp = (intptr_t) ct->byte_map_base;
if (is_simm32(disp)) {
- Address cardtable(noreg, obj, Address::times_1, disp);
- movb(cardtable, 0);
+ card_addr = Address(noreg, obj, Address::times_1, disp);
} else {
// By doing it as an ExternalAddress 'disp' could be converted to a rip-relative
// displacement and done in a single instruction given favorable mapping and a
@@ -4301,7 +4293,21 @@
// entry and that entry is not properly handled by the relocation code.
AddressLiteral cardtable((address)ct->byte_map_base, relocInfo::none);
Address index(noreg, obj, Address::times_1);
- movb(as_Address(ArrayAddress(cardtable, index)), 0);
+ card_addr = as_Address(ArrayAddress(cardtable, index));
+ }
+
+ int dirty = CardTableModRefBS::dirty_card_val();
+ if (UseCondCardMark) {
+ Label L_already_dirty;
+ if (UseConcMarkSweepGC) {
+ membar(Assembler::StoreLoad);
+ }
+ cmpb(card_addr, dirty);
+ jcc(Assembler::equal, L_already_dirty);
+ movb(card_addr, dirty);
+ bind(L_already_dirty);
+ } else {
+ movb(card_addr, dirty);
}
}
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -315,10 +315,6 @@
#endif // INCLUDE_ALL_GCS
- // split store_check(Register obj) to enhance instruction interleaving
- void store_check_part_1(Register obj);
- void store_check_part_2(Register obj);
-
// C 'boolean' to Java boolean: x == 0 ? 0 : 1
void c2bool(Register x);
--- a/hotspot/src/cpu/zero/vm/globals_zero.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/cpu/zero/vm/globals_zero.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -63,7 +63,8 @@
define_pd_global(bool, PreserveFramePointer, false);
-#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct) \
+#define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \
+ \
product(bool, UseFastEmptyMethods, true, \
"Use fast method entry code for empty methods") \
\
--- a/hotspot/src/os/aix/vm/decoder_aix.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/aix/vm/decoder_aix.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright 2013 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -38,8 +38,8 @@
virtual bool demangle(const char* symbol, char* buf, int buflen) { return false; } // demangled by getFuncName
- virtual bool decode(address addr, char* buf, int buflen, int* offset, const char* modulepath) {
- return (::getFuncName((codeptr_t)addr, buf, buflen, offset, 0, 0, 0) == 0);
+ virtual bool decode(address addr, char* buf, int buflen, int* offset, const char* modulepath, bool demangle) {
+ return (::getFuncName((codeptr_t)addr, buf, buflen, offset, 0, 0, 0, demangle) == 0);
}
virtual bool decode(address addr, char *buf, int buflen, int* offset, const void *base) {
ShouldNotReachHere();
--- a/hotspot/src/os/aix/vm/globals_aix.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/aix/vm/globals_aix.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -29,7 +29,7 @@
//
// Defines Aix specific flags. They are not available on other platforms.
//
-#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \
+#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct, range, constraint) \
\
/* Use 64K pages for virtual memory (shmat). */ \
product(bool, Use64KPages, true, \
--- a/hotspot/src/os/aix/vm/os_aix.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/aix/vm/os_aix.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1439,7 +1439,8 @@
}
bool os::dll_address_to_function_name(address addr, char *buf,
- int buflen, int *offset) {
+ int buflen, int *offset,
+ bool demangle) {
if (offset) {
*offset = -1;
}
@@ -1454,7 +1455,7 @@
}
// Go through Decoder::decode to call getFuncName which reads the name from the traceback table.
- return Decoder::decode(addr, buf, buflen, offset);
+ return Decoder::decode(addr, buf, buflen, offset, demangle);
}
static int getModuleName(codeptr_t pc, // [in] program counter
@@ -1653,7 +1654,7 @@
}
}
-void os::pd_print_cpu_info(outputStream* st) {
+void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
// cpu
st->print("CPU:");
st->print("total %d", os::processor_count());
@@ -3761,10 +3762,6 @@
return fetcher.result();
}
-// Not neede on Aix.
-// int os::Aix::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime) {
-// }
-
////////////////////////////////////////////////////////////////////////////////
// debug support
--- a/hotspot/src/os/aix/vm/porting_aix.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/aix/vm/porting_aix.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -114,7 +114,8 @@
int* p_displacement, // [out] optional: displacement (-1 if not available)
const struct tbtable** p_tb, // [out] optional: ptr to traceback table to get further
// information (NULL if not available)
- char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages
+ char* p_errmsg, size_t errmsglen,// [out] optional: user provided buffer for error messages
+ bool demangle // [in] whether to demangle the name
) {
struct tbtable* tb = 0;
unsigned int searchcount = 0;
@@ -216,15 +217,17 @@
p_name[0] = '\0';
// If it is a C++ name, try and demangle it using the Demangle interface (see demangle.h).
- char* rest;
- Name* const name = Demangle(buf, rest);
- if (name) {
- const char* const demangled_name = name->Text();
- if (demangled_name) {
- strncpy(p_name, demangled_name, namelen-1);
- p_name[namelen-1] = '\0';
+ if (demangle) {
+ char* rest;
+ Name* const name = Demangle(buf, rest);
+ if (name) {
+ const char* const demangled_name = name->Text();
+ if (demangled_name) {
+ strncpy(p_name, demangled_name, namelen-1);
+ p_name[namelen-1] = '\0';
+ }
+ delete name;
}
- delete name;
}
// Fallback: if demangling did not work, just provide the unmangled name.
@@ -325,7 +328,7 @@
int displacement = 0;
if (getFuncName((codeptr_t) p, funcname, sizeof(funcname), &displacement,
- NULL, NULL, 0) == 0) {
+ NULL, NULL, 0, true /* demangle */) == 0) {
if (funcname[0] != '\0') {
const char* const interned = dladdr_fixed_strings.intern(funcname);
info->dli_sname = interned;
--- a/hotspot/src/os/aix/vm/porting_aix.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/aix/vm/porting_aix.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -87,7 +87,8 @@
char* p_name, size_t namelen, // [out] optional: user provided buffer for the function name
int* p_displacement, // [out] optional: displacement
const struct tbtable** p_tb, // [out] optional: ptr to traceback table to get further information
- char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages
+ char* p_errmsg, size_t errmsglen,// [out] optional: user provided buffer for error messages
+ bool demangle = true // [in] whether to demangle the name
);
// -------------------------------------------------------------------------
--- a/hotspot/src/os/bsd/vm/decoder_machO.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/bsd/vm/decoder_machO.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,7 @@
virtual bool decode(address pc, char* buf, int buflen, int* offset,
const void* base);
virtual bool decode(address pc, char* buf, int buflen, int* offset,
- const char* module_path = NULL) {
+ const char* module_path, bool demangle) {
ShouldNotReachHere();
return false;
}
--- a/hotspot/src/os/bsd/vm/globals_bsd.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/bsd/vm/globals_bsd.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,19 +28,20 @@
//
// Defines Bsd specific flags. They are not available on other platforms.
//
-#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \
- product(bool, UseOprofile, false, \
- "enable support for Oprofile profiler") \
- \
- product(bool, UseBsdPosixThreadCPUClocks, true, \
- "enable fast Bsd Posix clocks where available") \
-/* NB: The default value of UseBsdPosixThreadCPUClocks may be \
- overridden in Arguments::parse_each_vm_init_arg. */ \
- \
- product(bool, UseHugeTLBFS, false, \
- "Use MAP_HUGETLB for large pages") \
- \
- product(bool, UseSHM, false, \
+#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct, range, constraint) \
+ \
+ product(bool, UseOprofile, false, \
+ "enable support for Oprofile profiler") \
+ \
+ /* NB: The default value of UseBsdPosixThreadCPUClocks may be */ \
+ /* overridden in Arguments::parse_each_vm_init_arg. */ \
+ product(bool, UseBsdPosixThreadCPUClocks, true, \
+ "enable fast Bsd Posix clocks where available") \
+ \
+ product(bool, UseHugeTLBFS, false, \
+ "Use MAP_HUGETLB for large pages") \
+ \
+ product(bool, UseSHM, false, \
"Use SYSV shared memory for large pages")
//
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -637,11 +637,6 @@
//////////////////////////////////////////////////////////////////////////////
// create new thread
-// check if it's safe to start a new thread
-static bool _thread_safety_check(Thread* thread) {
- return true;
-}
-
#ifdef __APPLE__
// library handle for calling objc_registerThreadWithCollector()
// without static linking to the libobjc library
@@ -681,15 +676,6 @@
OSThread* osthread = thread->osthread();
Monitor* sync = osthread->startThread_lock();
- // non floating stack BsdThreads needs extra check, see above
- if (!_thread_safety_check(thread)) {
- // notify parent thread
- MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
- osthread->set_state(ZOMBIE);
- sync->notify_all();
- return NULL;
- }
-
osthread->set_thread_id(os::Bsd::gettid());
#ifdef __APPLE__
@@ -1339,7 +1325,8 @@
#define MACH_MAXSYMLEN 256
bool os::dll_address_to_function_name(address addr, char *buf,
- int buflen, int *offset) {
+ int buflen, int *offset,
+ bool demangle) {
// buf is not optional, but offset is optional
assert(buf != NULL, "sanity check");
@@ -1349,7 +1336,7 @@
if (dladdr((void*)addr, &dlinfo) != 0) {
// see if we have a matching symbol
if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) {
- if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
+ if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) {
jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
}
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
@@ -1358,15 +1345,16 @@
// no matching symbol so try for just file info
if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
- buf, buflen, offset, dlinfo.dli_fname)) {
+ buf, buflen, offset, dlinfo.dli_fname, demangle)) {
return true;
}
}
// Handle non-dynamic manually:
if (dlinfo.dli_fbase != NULL &&
- Decoder::decode(addr, localbuf, MACH_MAXSYMLEN, offset, dlinfo.dli_fbase)) {
- if (!Decoder::demangle(localbuf, buf, buflen)) {
+ Decoder::decode(addr, localbuf, MACH_MAXSYMLEN, offset,
+ dlinfo.dli_fbase)) {
+ if (!(demangle && Decoder::demangle(localbuf, buf, buflen))) {
jio_snprintf(buf, buflen, "%s", localbuf);
}
return true;
@@ -1706,7 +1694,7 @@
os::Posix::print_load_average(st);
}
-void os::pd_print_cpu_info(outputStream* st) {
+void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
// Nothing to do for now.
}
@@ -2276,8 +2264,6 @@
return os::uncommit_memory(addr, size);
}
-static address _highest_vm_reserved_address = NULL;
-
// If 'fixed' is true, anon_mmap() will attempt to reserve anonymous memory
// at 'requested_addr'. If there are existing memory mappings at the same
// location, however, they will be overwritten. If 'fixed' is false,
@@ -2300,23 +2286,9 @@
addr = (char*)::mmap(requested_addr, bytes, PROT_NONE,
flags, -1, 0);
- if (addr != MAP_FAILED) {
- // anon_mmap() should only get called during VM initialization,
- // don't need lock (actually we can skip locking even it can be called
- // from multiple threads, because _highest_vm_reserved_address is just a
- // hint about the upper limit of non-stack memory regions.)
- if ((address)addr + bytes > _highest_vm_reserved_address) {
- _highest_vm_reserved_address = (address)addr + bytes;
- }
- }
-
return addr == MAP_FAILED ? NULL : addr;
}
-// Don't update _highest_vm_reserved_address, because there might be memory
-// regions above addr + size. If so, releasing a memory region only creates
-// a hole in the address space, it doesn't help prevent heap-stack collision.
-//
static int anon_munmap(char * addr, size_t size) {
return ::munmap(addr, size) == 0;
}
@@ -2490,15 +2462,7 @@
assert(bytes % os::vm_page_size() == 0, "reserving unexpected size block");
// Repeatedly allocate blocks until the block is allocated at the
- // right spot. Give up after max_tries. Note that reserve_memory() will
- // automatically update _highest_vm_reserved_address if the call is
- // successful. The variable tracks the highest memory address every reserved
- // by JVM. It is used to detect heap-stack collision if running with
- // fixed-stack BsdThreads. Because here we may attempt to reserve more
- // space than needed, it could confuse the collision detecting code. To
- // solve the problem, save current _highest_vm_reserved_address and
- // calculate the correct value before return.
- address old_highest = _highest_vm_reserved_address;
+ // right spot.
// Bsd mmap allows caller to pass an address as hint; give it a try first,
// if kernel honors the hint then we can return immediately.
@@ -2552,10 +2516,8 @@
}
if (i < max_tries) {
- _highest_vm_reserved_address = MAX2(old_highest, (address)requested_addr + bytes);
return requested_addr;
} else {
- _highest_vm_reserved_address = old_highest;
return NULL;
}
}
@@ -3715,12 +3677,6 @@
return fetcher.result();
}
-int os::Bsd::safe_cond_timedwait(pthread_cond_t *_cond,
- pthread_mutex_t *_mutex,
- const struct timespec *_abstime) {
- return pthread_cond_timedwait(_cond, _mutex, _abstime);
-}
-
////////////////////////////////////////////////////////////////////////////////
// debug support
@@ -4286,7 +4242,7 @@
// In that case, we should propagate the notify to another waiter.
while (_Event < 0) {
- status = os::Bsd::safe_cond_timedwait(_cond, _mutex, &abst);
+ status = pthread_cond_timedwait(_cond, _mutex, &abst);
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
pthread_cond_destroy(_cond);
pthread_cond_init(_cond, NULL);
@@ -4492,7 +4448,7 @@
if (time == 0) {
status = pthread_cond_wait(_cond, _mutex);
} else {
- status = os::Bsd::safe_cond_timedwait(_cond, _mutex, &absTime);
+ status = pthread_cond_timedwait(_cond, _mutex, &absTime);
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
pthread_cond_destroy(_cond);
pthread_cond_init(_cond, NULL);
--- a/hotspot/src/os/bsd/vm/os_bsd.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/bsd/vm/os_bsd.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -30,9 +30,6 @@
// Information about the protection of the page at address '0' on this os.
static bool zero_page_read_protected() { return true; }
-// pthread_getattr_np comes with BsdThreads-0.9-7 on RedHat 7.1
-typedef int (*pthread_getattr_func_type)(pthread_t, pthread_attr_t *);
-
#ifdef __APPLE__
// Mac OS X doesn't support clock_gettime. Stub out the type, it is
// unused
@@ -145,9 +142,6 @@
// none present
- // BsdThreads work-around for 6292965
- static int safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime);
-
private:
typedef int (*sched_getcpu_func_t)(void);
typedef int (*numa_node_to_cpus_func_t)(int node, unsigned long *buffer, int bufferlen);
--- a/hotspot/src/os/linux/vm/globals_linux.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/linux/vm/globals_linux.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,14 +28,15 @@
//
// Defines Linux specific flags. They are not available on other platforms.
//
-#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \
+#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct, range, constraint) \
+ \
product(bool, UseOprofile, false, \
"enable support for Oprofile profiler") \
\
+ /* NB: The default value of UseLinuxPosixThreadCPUClocks may be */ \
+ /* overridden in Arguments::parse_each_vm_init_arg. */ \
product(bool, UseLinuxPosixThreadCPUClocks, true, \
"enable fast Linux Posix clocks where available") \
-/* NB: The default value of UseLinuxPosixThreadCPUClocks may be \
- overridden in Arguments::parse_each_vm_init_arg. */ \
\
product(bool, UseHugeTLBFS, false, \
"Use MAP_HUGETLB for large pages") \
--- a/hotspot/src/os/linux/vm/os_linux.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -135,8 +135,6 @@
pthread_t os::Linux::_main_thread;
int os::Linux::_page_size = -1;
const int os::Linux::_vm_default_page_size = (8 * K);
-bool os::Linux::_is_floating_stack = false;
-bool os::Linux::_is_NPTL = false;
bool os::Linux::_supports_fast_thread_cpu_time = false;
const char * os::Linux::_glibc_version = NULL;
const char * os::Linux::_libpthread_version = NULL;
@@ -150,8 +148,6 @@
static sigset_t check_signal_done;
static bool check_signals = true;
-static pid_t _initial_pid = 0;
-
// Signal number used to suspend/resume a thread
// do not use any signal number less than SIGSEGV, see 4355769
@@ -223,18 +219,10 @@
//
// Returns the kernel thread id of the currently running thread. Kernel
// thread id is used to access /proc.
-//
-// (Note that getpid() on LinuxThreads returns kernel thread id too; but
-// on NPTL, it returns the same pid for all threads, as required by POSIX.)
-//
pid_t os::Linux::gettid() {
int rslt = syscall(SYS_gettid);
- if (rslt == -1) {
- // old kernel, no NPTL support
- return getpid();
- } else {
- return (pid_t)rslt;
- }
+ assert(rslt != -1, "must be."); // old linuxthreads implementation?
+ return (pid_t)rslt;
}
// Most versions of linux have a bug where the number of processors are
@@ -508,68 +496,48 @@
// detecting pthread library
void os::Linux::libpthread_init() {
- // Save glibc and pthread version strings. Note that _CS_GNU_LIBC_VERSION
- // and _CS_GNU_LIBPTHREAD_VERSION are supported in glibc >= 2.3.2. Use a
- // generic name for earlier versions.
- // Define macros here so we can build HotSpot on old systems.
-#ifndef _CS_GNU_LIBC_VERSION
- #define _CS_GNU_LIBC_VERSION 2
-#endif
-#ifndef _CS_GNU_LIBPTHREAD_VERSION
- #define _CS_GNU_LIBPTHREAD_VERSION 3
+ // Save glibc and pthread version strings.
+#if !defined(_CS_GNU_LIBC_VERSION) || \
+ !defined(_CS_GNU_LIBPTHREAD_VERSION)
+ #error "glibc too old (< 2.3.2)"
#endif
size_t n = confstr(_CS_GNU_LIBC_VERSION, NULL, 0);
- if (n > 0) {
- char *str = (char *)malloc(n, mtInternal);
- confstr(_CS_GNU_LIBC_VERSION, str, n);
- os::Linux::set_glibc_version(str);
- } else {
- // _CS_GNU_LIBC_VERSION is not supported, try gnu_get_libc_version()
- static char _gnu_libc_version[32];
- jio_snprintf(_gnu_libc_version, sizeof(_gnu_libc_version),
- "glibc %s %s", gnu_get_libc_version(), gnu_get_libc_release());
- os::Linux::set_glibc_version(_gnu_libc_version);
- }
+ assert(n > 0, "cannot retrieve glibc version");
+ char *str = (char *)malloc(n, mtInternal);
+ confstr(_CS_GNU_LIBC_VERSION, str, n);
+ os::Linux::set_glibc_version(str);
n = confstr(_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
- if (n > 0) {
- char *str = (char *)malloc(n, mtInternal);
- confstr(_CS_GNU_LIBPTHREAD_VERSION, str, n);
- // Vanilla RH-9 (glibc 2.3.2) has a bug that confstr() always tells
- // us "NPTL-0.29" even we are running with LinuxThreads. Check if this
- // is the case. LinuxThreads has a hard limit on max number of threads.
- // So sysconf(_SC_THREAD_THREADS_MAX) will return a positive value.
- // On the other hand, NPTL does not have such a limit, sysconf()
- // will return -1 and errno is not changed. Check if it is really NPTL.
- if (strcmp(os::Linux::glibc_version(), "glibc 2.3.2") == 0 &&
- strstr(str, "NPTL") &&
- sysconf(_SC_THREAD_THREADS_MAX) > 0) {
- free(str);
- os::Linux::set_libpthread_version("linuxthreads");
- } else {
- os::Linux::set_libpthread_version(str);
- }
- } else {
- // glibc before 2.3.2 only has LinuxThreads.
- os::Linux::set_libpthread_version("linuxthreads");
- }
-
- if (strstr(libpthread_version(), "NPTL")) {
- os::Linux::set_is_NPTL();
- } else {
- os::Linux::set_is_LinuxThreads();
- }
-
- // LinuxThreads have two flavors: floating-stack mode, which allows variable
- // stack size; and fixed-stack mode. NPTL is always floating-stack.
- if (os::Linux::is_NPTL() || os::Linux::supports_variable_stack_size()) {
- os::Linux::set_is_floating_stack();
- }
+ assert(n > 0, "cannot retrieve pthread version");
+ str = (char *)malloc(n, mtInternal);
+ confstr(_CS_GNU_LIBPTHREAD_VERSION, str, n);
+ os::Linux::set_libpthread_version(str);
}
/////////////////////////////////////////////////////////////////////////////
-// thread stack
+// thread stack expansion
+
+// os::Linux::manually_expand_stack() takes care of expanding the thread
+// stack. Note that this is normally not needed: pthread stacks allocate
+// thread stack using mmap() without MAP_NORESERVE, so the stack is already
+// committed. Therefore it is not necessary to expand the stack manually.
+//
+// Manually expanding the stack was historically needed on LinuxThreads
+// thread stacks, which were allocated with mmap(MAP_GROWSDOWN). Nowadays
+// it is kept to deal with very rare corner cases:
+//
+// For one, user may run the VM on an own implementation of threads
+// whose stacks are - like the old LinuxThreads - implemented using
+// mmap(MAP_GROWSDOWN).
+//
+// Also, this coding may be needed if the VM is running on the primordial
+// thread. Normally we avoid running on the primordial thread; however,
+// user may still invoke the VM on the primordial thread.
+//
+// The following historical comment describes the details about running
+// on a thread stack allocated with mmap(MAP_GROWSDOWN):
+
// Force Linux kernel to expand current thread stack. If "bottom" is close
// to the stack guard, caller should block all signals.
@@ -593,10 +561,7 @@
// stack overflow detection.
//
// Newer version of LinuxThreads (since glibc-2.2, or, RH-7.x) and NPTL do
-// not use this flag. However, the stack of initial thread is not created
-// by pthread, it is still MAP_GROWSDOWN. Also it's possible (though
-// unlikely) that user code can create a thread with MAP_GROWSDOWN stack
-// and then attach the thread to JVM.
+// not use MAP_GROWSDOWN.
//
// To get around the problem and allow stack banging on Linux, we need to
// manually expand thread stack after receiving the SIGSEGV.
@@ -671,45 +636,6 @@
//////////////////////////////////////////////////////////////////////////////
// create new thread
-static address highest_vm_reserved_address();
-
-// check if it's safe to start a new thread
-static bool _thread_safety_check(Thread* thread) {
- if (os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack()) {
- // Fixed stack LinuxThreads (SuSE Linux/x86, and some versions of Redhat)
- // Heap is mmap'ed at lower end of memory space. Thread stacks are
- // allocated (MAP_FIXED) from high address space. Every thread stack
- // occupies a fixed size slot (usually 2Mbytes, but user can change
- // it to other values if they rebuild LinuxThreads).
- //
- // Problem with MAP_FIXED is that mmap() can still succeed even part of
- // the memory region has already been mmap'ed. That means if we have too
- // many threads and/or very large heap, eventually thread stack will
- // collide with heap.
- //
- // Here we try to prevent heap/stack collision by comparing current
- // stack bottom with the highest address that has been mmap'ed by JVM
- // plus a safety margin for memory maps created by native code.
- //
- // This feature can be disabled by setting ThreadSafetyMargin to 0
- //
- if (ThreadSafetyMargin > 0) {
- address stack_bottom = os::current_stack_base() - os::current_stack_size();
-
- // not safe if our stack extends below the safety margin
- return stack_bottom - ThreadSafetyMargin >= highest_vm_reserved_address();
- } else {
- return true;
- }
- } else {
- // Floating stack LinuxThreads or NPTL:
- // Unlike fixed stack LinuxThreads, thread stacks are not MAP_FIXED. When
- // there's not enough space left, pthread_create() will fail. If we come
- // here, that means enough space has been reserved for stack.
- return true;
- }
-}
-
// Thread start routine for all newly created threads
static void *java_start(Thread *thread) {
// Try to randomize the cache line index of hot stack frames.
@@ -726,15 +652,6 @@
OSThread* osthread = thread->osthread();
Monitor* sync = osthread->startThread_lock();
- // non floating stack LinuxThreads needs extra check, see above
- if (!_thread_safety_check(thread)) {
- // notify parent thread
- MutexLockerEx ml(sync, Mutex::_no_safepoint_check_flag);
- osthread->set_state(ZOMBIE);
- sync->notify_all();
- return NULL;
- }
-
// thread_id is kernel thread id (similar to Solaris LWP id)
osthread->set_thread_id(os::Linux::gettid());
@@ -833,12 +750,6 @@
ThreadState state;
{
- // Serialize thread creation if we are running with fixed stack LinuxThreads
- bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
- if (lock) {
- os::Linux::createThread_lock()->lock_without_safepoint_check();
- }
-
pthread_t tid;
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
@@ -851,7 +762,6 @@
// Need to clean up stuff we've allocated so far
thread->set_osthread(NULL);
delete osthread;
- if (lock) os::Linux::createThread_lock()->unlock();
return false;
}
@@ -866,10 +776,6 @@
sync_with_child->wait(Mutex::_no_safepoint_check_flag);
}
}
-
- if (lock) {
- os::Linux::createThread_lock()->unlock();
- }
}
// Aborted due to thread limit being reached
@@ -1497,7 +1403,6 @@
// Die immediately, no exit hook, no abort hook, no cleanup.
void os::die() {
- // _exit() on LinuxThreads only kills current thread
::abort();
}
@@ -1520,24 +1425,7 @@
intx os::current_thread_id() { return (intx)pthread_self(); }
int os::current_process_id() {
-
- // Under the old linux thread library, linux gives each thread
- // its own process id. Because of this each thread will return
- // a different pid if this method were to return the result
- // of getpid(2). Linux provides no api that returns the pid
- // of the launcher thread for the vm. This implementation
- // returns a unique pid, the pid of the launcher thread
- // that starts the vm 'process'.
-
- // Under the NPTL, getpid() returns the same pid as the
- // launcher thread rather than a unique pid per thread.
- // Use gettid() if you want the old pre NPTL behaviour.
-
- // if you are looking for the result of a call to getpid() that
- // returns a unique pid for the calling thread, then look at the
- // OSThread::thread_id() method in osThread_linux.hpp file
-
- return (int)(_initial_pid ? _initial_pid : getpid());
+ return ::getpid();
}
// DLL functions
@@ -1623,7 +1511,8 @@
}
bool os::dll_address_to_function_name(address addr, char *buf,
- int buflen, int *offset) {
+ int buflen, int *offset,
+ bool demangle) {
// buf is not optional, but offset is optional
assert(buf != NULL, "sanity check");
@@ -1632,7 +1521,7 @@
if (dladdr((void*)addr, &dlinfo) != 0) {
// see if we have a matching symbol
if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) {
- if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
+ if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) {
jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
}
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
@@ -1641,7 +1530,7 @@
// no matching symbol so try for just file info
if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
- buf, buflen, offset, dlinfo.dli_fname)) {
+ buf, buflen, offset, dlinfo.dli_fname, demangle)) {
return true;
}
}
@@ -2183,9 +2072,6 @@
st->print("libc:");
st->print("%s ", os::Linux::glibc_version());
st->print("%s ", os::Linux::libpthread_version());
- if (os::Linux::is_LinuxThreads()) {
- st->print("(%s stack)", os::Linux::is_floating_stack() ? "floating" : "fixed");
- }
st->cr();
}
@@ -2215,12 +2101,52 @@
st->cr();
}
-void os::pd_print_cpu_info(outputStream* st) {
- st->print("\n/proc/cpuinfo:\n");
- if (!_print_ascii_file("/proc/cpuinfo", st)) {
- st->print(" <Not Available>");
- }
- st->cr();
+// Print the first "model name" line and the first "flags" line
+// that we find and nothing more. We assume "model name" comes
+// before "flags" so if we find a second "model name", then the
+// "flags" field is considered missing.
+static bool print_model_name_and_flags(outputStream* st, char* buf, size_t buflen) {
+#if defined(IA32) || defined(AMD64)
+ // Other platforms have less repetitive cpuinfo files
+ FILE *fp = fopen("/proc/cpuinfo", "r");
+ if (fp) {
+ while (!feof(fp)) {
+ if (fgets(buf, buflen, fp)) {
+ // Assume model name comes before flags
+ bool model_name_printed = false;
+ if (strstr(buf, "model name") != NULL) {
+ if (!model_name_printed) {
+ st->print_raw("\nCPU Model and flags from /proc/cpuinfo:\n");
+ st->print_raw(buf);
+ model_name_printed = true;
+ } else {
+ // model name printed but not flags? Odd, just return
+ fclose(fp);
+ return true;
+ }
+ }
+ // print the flags line too
+ if (strstr(buf, "flags") != NULL) {
+ st->print_raw(buf);
+ fclose(fp);
+ return true;
+ }
+ }
+ }
+ fclose(fp);
+ }
+#endif // x86 platforms
+ return false;
+}
+
+void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
+ // Only print the model name if the platform provides this as a summary
+ if (!print_model_name_and_flags(st, buf, buflen)) {
+ st->print("\n/proc/cpuinfo:\n");
+ if (!_print_ascii_file("/proc/cpuinfo", st)) {
+ st->print_cr(" <Not Available>");
+ }
+ }
}
void os::print_siginfo(outputStream* st, void* siginfo) {
@@ -3044,8 +2970,6 @@
return os::uncommit_memory(addr, size);
}
-static address _highest_vm_reserved_address = NULL;
-
// If 'fixed' is true, anon_mmap() will attempt to reserve anonymous memory
// at 'requested_addr'. If there are existing memory mappings at the same
// location, however, they will be overwritten. If 'fixed' is false,
@@ -3068,23 +2992,9 @@
addr = (char*)::mmap(requested_addr, bytes, PROT_NONE,
flags, -1, 0);
- if (addr != MAP_FAILED) {
- // anon_mmap() should only get called during VM initialization,
- // don't need lock (actually we can skip locking even it can be called
- // from multiple threads, because _highest_vm_reserved_address is just a
- // hint about the upper limit of non-stack memory regions.)
- if ((address)addr + bytes > _highest_vm_reserved_address) {
- _highest_vm_reserved_address = (address)addr + bytes;
- }
- }
-
return addr == MAP_FAILED ? NULL : addr;
}
-// Don't update _highest_vm_reserved_address, because there might be memory
-// regions above addr + size. If so, releasing a memory region only creates
-// a hole in the address space, it doesn't help prevent heap-stack collision.
-//
static int anon_munmap(char * addr, size_t size) {
return ::munmap(addr, size) == 0;
}
@@ -3098,10 +3008,6 @@
return anon_munmap(addr, size);
}
-static address highest_vm_reserved_address() {
- return _highest_vm_reserved_address;
-}
-
static bool linux_mprotect(char* addr, size_t size, int prot) {
// Linux wants the mprotect address argument to be page aligned.
char* bottom = (char*)align_size_down((intptr_t)addr, os::Linux::page_size());
@@ -3718,15 +3624,7 @@
assert(bytes % os::vm_page_size() == 0, "reserving unexpected size block");
// Repeatedly allocate blocks until the block is allocated at the
- // right spot. Give up after max_tries. Note that reserve_memory() will
- // automatically update _highest_vm_reserved_address if the call is
- // successful. The variable tracks the highest memory address every reserved
- // by JVM. It is used to detect heap-stack collision if running with
- // fixed-stack LinuxThreads. Because here we may attempt to reserve more
- // space than needed, it could confuse the collision detecting code. To
- // solve the problem, save current _highest_vm_reserved_address and
- // calculate the correct value before return.
- address old_highest = _highest_vm_reserved_address;
+ // right spot.
// Linux mmap allows caller to pass an address as hint; give it a try first,
// if kernel honors the hint then we can return immediately.
@@ -3780,10 +3678,8 @@
}
if (i < max_tries) {
- _highest_vm_reserved_address = MAX2(old_highest, (address)requested_addr + bytes);
return requested_addr;
} else {
- _highest_vm_reserved_address = old_highest;
return NULL;
}
}
@@ -4627,16 +4523,6 @@
char dummy; // used to get a guess on initial stack address
// first_hrtime = gethrtime();
- // With LinuxThreads the JavaMain thread pid (primordial thread)
- // is different than the pid of the java launcher thread.
- // So, on Linux, the launcher thread pid is passed to the VM
- // via the sun.java.launcher.pid property.
- // Use this property instead of getpid() if it was correctly passed.
- // See bug 6351349.
- pid_t java_launcher_pid = (pid_t) Arguments::sun_java_launcher_pid();
-
- _initial_pid = (java_launcher_pid > 0) ? java_launcher_pid : getpid();
-
clock_tics_per_sec = sysconf(_SC_CLK_TCK);
init_random(1234567);
@@ -4769,9 +4655,8 @@
Linux::libpthread_init();
if (PrintMiscellaneous && (Verbose || WizardMode)) {
- tty->print_cr("[HotSpot is running with %s, %s(%s)]\n",
- Linux::glibc_version(), Linux::libpthread_version(),
- Linux::is_floating_stack() ? "floating stack" : "fixed stack");
+ tty->print_cr("[HotSpot is running with %s, %s]\n",
+ Linux::glibc_version(), Linux::libpthread_version());
}
if (UseNUMA) {
@@ -4946,22 +4831,6 @@
return fetcher.result();
}
-int os::Linux::safe_cond_timedwait(pthread_cond_t *_cond,
- pthread_mutex_t *_mutex,
- const struct timespec *_abstime) {
- if (is_NPTL()) {
- return pthread_cond_timedwait(_cond, _mutex, _abstime);
- } else {
- // 6292965: LinuxThreads pthread_cond_timedwait() resets FPU control
- // word back to default 64bit precision if condvar is signaled. Java
- // wants 53bit precision. Save and restore current value.
- int fpu = get_fpu_control_word();
- int status = pthread_cond_timedwait(_cond, _mutex, _abstime);
- set_fpu_control_word(fpu);
- return status;
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
// debug support
@@ -5585,7 +5454,7 @@
// In that case, we should propagate the notify to another waiter.
while (_Event < 0) {
- status = os::Linux::safe_cond_timedwait(_cond, _mutex, &abst);
+ status = pthread_cond_timedwait(_cond, _mutex, &abst);
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
pthread_cond_destroy(_cond);
pthread_cond_init(_cond, os::Linux::condAttr());
@@ -5813,7 +5682,7 @@
status = pthread_cond_wait(&_cond[_cur_index], _mutex);
} else {
_cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;
- status = os::Linux::safe_cond_timedwait(&_cond[_cur_index], _mutex, &absTime);
+ status = pthread_cond_timedwait(&_cond[_cur_index], _mutex, &absTime);
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
pthread_cond_destroy(&_cond[_cur_index]);
pthread_cond_init(&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr());
--- a/hotspot/src/os/linux/vm/os_linux.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/linux/vm/os_linux.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,9 +27,6 @@
// Linux_OS defines the interface to Linux operating systems
-// pthread_getattr_np comes with LinuxThreads-0.9-7 on RedHat 7.1
-typedef int (*pthread_getattr_func_type)(pthread_t, pthread_attr_t *);
-
// Information about the protection of the page at address '0' on this os.
static bool zero_page_read_protected() { return true; }
@@ -63,8 +60,6 @@
static const char *_glibc_version;
static const char *_libpthread_version;
- static bool _is_floating_stack;
- static bool _is_NPTL;
static bool _supports_fast_thread_cpu_time;
static GrowableArray<int>* _cpu_to_node;
@@ -90,10 +85,6 @@
static bool supports_variable_stack_size();
- static void set_is_NPTL() { _is_NPTL = true; }
- static void set_is_LinuxThreads() { _is_NPTL = false; }
- static void set_is_floating_stack() { _is_floating_stack = true; }
-
static void rebuild_cpu_to_node_map();
static GrowableArray<int>* cpu_to_node() { return _cpu_to_node; }
@@ -178,14 +169,6 @@
static const char *glibc_version() { return _glibc_version; }
static const char *libpthread_version() { return _libpthread_version; }
- // NPTL or LinuxThreads?
- static bool is_LinuxThreads() { return !_is_NPTL; }
- static bool is_NPTL() { return _is_NPTL; }
-
- // NPTL is always floating stack. LinuxThreads could be using floating
- // stack or fixed stack.
- static bool is_floating_stack() { return _is_floating_stack; }
-
static void libpthread_init();
static bool libnuma_init();
static void* libnuma_dlsym(void* handle, const char* name);
@@ -234,9 +217,6 @@
// none present
- // LinuxThreads work-around for 6292965
- static int safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime);
-
private:
typedef int (*sched_getcpu_func_t)(void);
typedef int (*numa_node_to_cpus_func_t)(int node, unsigned long *buffer, int bufferlen);
--- a/hotspot/src/os/solaris/vm/globals_solaris.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/solaris/vm/globals_solaris.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
//
// Defines Solaris specific flags. They are not available on other platforms.
//
-#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \
+#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct, range, constraint) \
\
product(bool, UseExtendedFileIO, true, \
"Enable workaround for limitations of stdio FILE structure")
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1627,7 +1627,8 @@
static dladdr1_func_type dladdr1_func = NULL;
bool os::dll_address_to_function_name(address addr, char *buf,
- int buflen, int * offset) {
+ int buflen, int * offset,
+ bool demangle) {
// buf is not optional, but offset is optional
assert(buf != NULL, "sanity check");
@@ -1655,7 +1656,7 @@
if (dlinfo.dli_saddr != NULL &&
(char *)dlinfo.dli_saddr + info->st_size > (char *)addr) {
if (dlinfo.dli_sname != NULL) {
- if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
+ if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) {
jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
}
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
@@ -1665,7 +1666,7 @@
// no matching symbol so try for just file info
if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
- buf, buflen, offset, dlinfo.dli_fname)) {
+ buf, buflen, offset, dlinfo.dli_fname, demangle)) {
return true;
}
}
@@ -1679,7 +1680,7 @@
if (dladdr((void *)addr, &dlinfo) != 0) {
// see if we have a matching symbol
if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) {
- if (!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
+ if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) {
jio_snprintf(buf, buflen, dlinfo.dli_sname);
}
if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
@@ -1688,7 +1689,7 @@
// no matching symbol so try for just file info
if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
- buf, buflen, offset, dlinfo.dli_fname)) {
+ buf, buflen, offset, dlinfo.dli_fname, demangle)) {
return true;
}
}
@@ -1996,7 +1997,7 @@
return status;
}
-void os::pd_print_cpu_info(outputStream* st) {
+void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
// Nothing to do for now.
}
--- a/hotspot/src/os/windows/vm/decoder_windows.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/windows/vm/decoder_windows.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -162,7 +162,7 @@
// current function and comparing the result
address addr = (address)Decoder::demangle;
char buf[MAX_PATH];
- if (decode(addr, buf, sizeof(buf), NULL)) {
+ if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) {
_can_decode_in_vm = !strcmp(buf, "Decoder::demangle");
}
}
@@ -187,7 +187,7 @@
}
-bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath) {
+bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath, bool demangle_name) {
if (_pfnSymGetSymFromAddr64 != NULL) {
PIMAGEHLP_SYMBOL64 pSymbol;
char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)];
@@ -197,7 +197,7 @@
DWORD64 displacement;
if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
if (buf != NULL) {
- if (demangle(pSymbol->Name, buf, buflen)) {
+ if (!(demangle_name && demangle(pSymbol->Name, buf, buflen))) {
jio_snprintf(buf, buflen, "%s", pSymbol->Name);
}
}
--- a/hotspot/src/os/windows/vm/decoder_windows.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/windows/vm/decoder_windows.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -60,7 +60,7 @@
bool can_decode_C_frame_in_vm() const;
bool demangle(const char* symbol, char *buf, int buflen);
- bool decode(address addr, char *buf, int buflen, int* offset, const char* modulepath = NULL);
+ bool decode(address addr, char *buf, int buflen, int* offset, const char* modulepath, bool demangle);
bool decode(address addr, char *buf, int buflen, int* offset, const void* base) {
ShouldNotReachHere();
return false;
--- a/hotspot/src/os/windows/vm/globals_windows.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/windows/vm/globals_windows.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,8 +28,7 @@
//
// Defines Windows specific flags. They are not available on other platforms.
//
-#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, \
- diagnostic, notproduct) \
+#define RUNTIME_OS_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct, range, constraint) \
\
product(bool, UseUTCFileTimestamp, true, \
"Adjust the timestamp returned from stat() to be UTC")
--- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1369,11 +1369,12 @@
}
bool os::dll_address_to_function_name(address addr, char *buf,
- int buflen, int *offset) {
+ int buflen, int *offset,
+ bool demangle) {
// buf is not optional, but offset is optional
assert(buf != NULL, "sanity check");
- if (Decoder::decode(addr, buf, buflen, offset)) {
+ if (Decoder::decode(addr, buf, buflen, offset, demangle)) {
return true;
}
if (offset != NULL) *offset = -1;
@@ -1732,7 +1733,7 @@
st->cr();
}
-void os::pd_print_cpu_info(outputStream* st) {
+void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
// Nothing to do for now.
}
--- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -10,7 +10,7 @@
* 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 hat
+ * 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
--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -619,53 +619,14 @@
#ifdef AMD64
size_t os::Linux::min_stack_allowed = 64 * K;
-
-// amd64: pthread on amd64 is always in floating stack mode
-bool os::Linux::supports_variable_stack_size() { return true; }
#else
size_t os::Linux::min_stack_allowed = (48 DEBUG_ONLY(+4))*K;
-
-#ifdef __GNUC__
-#define GET_GS() ({int gs; __asm__ volatile("movw %%gs, %w0":"=q"(gs)); gs&0xffff;})
-#endif
-
-// Test if pthread library can support variable thread stack size. LinuxThreads
-// in fixed stack mode allocates 2M fixed slot for each thread. LinuxThreads
-// in floating stack mode and NPTL support variable stack size.
-bool os::Linux::supports_variable_stack_size() {
- if (os::Linux::is_NPTL()) {
- // NPTL, yes
- return true;
+#endif // AMD64
- } else {
- // Note: We can't control default stack size when creating a thread.
- // If we use non-default stack size (pthread_attr_setstacksize), both
- // floating stack and non-floating stack LinuxThreads will return the
- // same value. This makes it impossible to implement this function by
- // detecting thread stack size directly.
- //
- // An alternative approach is to check %gs. Fixed-stack LinuxThreads
- // do not use %gs, so its value is 0. Floating-stack LinuxThreads use
- // %gs (either as LDT selector or GDT selector, depending on kernel)
- // to access thread specific data.
- //
- // Note that %gs is a reserved glibc register since early 2001, so
- // applications are not allowed to change its value (Ulrich Drepper from
- // Redhat confirmed that all known offenders have been modified to use
- // either %fs or TSD). In the worst case scenario, when VM is embedded in
- // a native application that plays with %gs, we might see non-zero %gs
- // even LinuxThreads is running in fixed stack mode. As the result, we'll
- // return true and skip _thread_safety_check(), so we may not be able to
- // detect stack-heap collisions. But otherwise it's harmless.
- //
-#ifdef __GNUC__
- return (GET_GS() != 0);
-#else
- return false;
-#endif
- }
+// Test if pthread library can support variable thread stack size.
+bool os::Linux::supports_variable_stack_size() {
+ return true;
}
-#endif // AMD64
// return default stack size for thr_type
size_t os::Linux::default_stack_size(os::ThreadType thr_type) {
--- a/hotspot/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -40,8 +40,7 @@
// actual memory pages are committed on demand.
//
// If an application creates and destroys a lot of threads, usually the
-// stack space freed by a thread will soon get reused by new thread
-// (this is especially true in NPTL or LinuxThreads in fixed-stack mode).
+// stack space freed by a thread will soon get reused by new thread.
// No memory page in _sp_map is wasted.
//
// However, it's still possible that we might end up populating &
--- a/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/tools/ProjectCreator/WinGammaPlatformVC10.java Thu Jun 25 09:48:50 2015 -0700
@@ -363,9 +363,6 @@
// Set /On option
addAttr(rv, "Optimization", opt);
- // Set /FR option.
- addAttr(rv, "BrowseInformation", "true");
- addAttr(rv, "BrowseInformationFile", "$(IntDir)");
// Set /MD option.
addAttr(rv, "RuntimeLibrary", "MultiThreadedDLL");
// Set /Oy- option
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1619,6 +1619,9 @@
LIR_Opr dirty = LIR_OprFact::intConst(CardTableModRefBS::dirty_card_val());
if (UseCondCardMark) {
LIR_Opr cur_value = new_register(T_INT);
+ if (UseConcMarkSweepGC) {
+ __ membar_storeload();
+ }
__ move(card_addr, cur_value);
LabelObj* L_already_dirty = new LabelObj();
--- a/hotspot/src/share/vm/c1/c1_globals.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/c1/c1_globals.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,4 +25,4 @@
#include "precompiled.hpp"
#include "c1/c1_globals.hpp"
-C1_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG)
+C1_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG, IGNORE_RANGE, IGNORE_CONSTRAINT)
--- a/hotspot/src/share/vm/c1/c1_globals.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/c1/c1_globals.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -60,7 +60,7 @@
//
// Defines all global flags used by the client compiler.
//
-#define C1_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \
+#define C1_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct, range, constraint) \
\
/* Printing */ \
notproduct(bool, PrintC1Statistics, false, \
@@ -148,6 +148,7 @@
\
product(intx, ValueMapInitialSize, 11, \
"Initial size of a value map") \
+ range(1, NOT_LP64(1*K) LP64_ONLY(32*K)) \
\
product(intx, ValueMapMaxLoopSize, 8, \
"maximum size of a loop optimized by global value numbering") \
@@ -191,6 +192,7 @@
\
develop(intx, NestedInliningSizeRatio, 90, \
"Percentage of prev. allowed inline size in recursive inlining") \
+ range(0, 100) \
\
notproduct(bool, PrintIRWithLIR, false, \
"Print IR instructions with generated LIR") \
@@ -338,10 +340,15 @@
diagnostic(bool, C1PatchInvokeDynamic, true, \
"Patch invokedynamic appendix not known at compile time") \
\
-
-
// Read default values for c1 globals
-C1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG)
+C1_FLAGS(DECLARE_DEVELOPER_FLAG, \
+ DECLARE_PD_DEVELOPER_FLAG, \
+ DECLARE_PRODUCT_FLAG, \
+ DECLARE_PD_PRODUCT_FLAG, \
+ DECLARE_DIAGNOSTIC_FLAG, \
+ DECLARE_NOTPRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
#endif // SHARE_VM_C1_C1_GLOBALS_HPP
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -949,8 +949,7 @@
assert(runtime_visible_annotations != NULL, "null visible annotations");
parse_annotations(runtime_visible_annotations,
runtime_visible_annotations_length,
- parsed_annotations,
- CHECK);
+ parsed_annotations);
cfs->skip_u1(runtime_visible_annotations_length, CHECK);
} else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
@@ -1643,7 +1642,6 @@
index = skip_annotation(buffer, limit, index);
break;
default:
- assert(false, "annotation tag");
return limit; // bad tag byte
}
return index;
@@ -1651,8 +1649,7 @@
// Sift through annotations, looking for those significant to the VM:
void ClassFileParser::parse_annotations(u1* buffer, int limit,
- ClassFileParser::AnnotationCollector* coll,
- TRAPS) {
+ ClassFileParser::AnnotationCollector* coll) {
// annotations := do(nann:u2) {annotation}
int index = 0;
if ((index += 2) >= limit) return; // read nann
@@ -2286,8 +2283,7 @@
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
parse_annotations(runtime_visible_annotations,
- runtime_visible_annotations_length, &parsed_annotations,
- CHECK_(nullHandle));
+ runtime_visible_annotations_length, &parsed_annotations);
cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle));
} else if (method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
@@ -2951,8 +2947,7 @@
assert(runtime_visible_annotations != NULL, "null visible annotations");
parse_annotations(runtime_visible_annotations,
runtime_visible_annotations_length,
- parsed_annotations,
- CHECK);
+ parsed_annotations);
cfs->skip_u1(runtime_visible_annotations_length, CHECK);
} else if (tag == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -295,8 +295,7 @@
int skip_annotation_value(u1* buffer, int limit, int index);
void parse_annotations(u1* buffer, int limit,
/* Results (currently, only one result is supported): */
- AnnotationCollector* result,
- TRAPS);
+ AnnotationCollector* result);
// Final setup
unsigned int compute_oop_map_count(instanceKlassHandle super,
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "memory/metaspaceShared.hpp"
+#include "prims/jvm.h"
#include "utilities/numberSeq.hpp"
#include <sys/stat.h>
@@ -32,11 +33,11 @@
//
// The compact hash table writer implementations
//
-CompactHashtableWriter::CompactHashtableWriter(const char* table_name,
+CompactHashtableWriter::CompactHashtableWriter(int table_type,
int num_entries,
CompactHashtableStats* stats) {
assert(DumpSharedSpaces, "dump-time only");
- _table_name = table_name;
+ _type = table_type;
_num_entries = num_entries;
_num_buckets = number_of_buckets(_num_entries);
_buckets = NEW_C_HEAP_ARRAY(Entry*, _num_buckets, mtSymbol);
@@ -99,7 +100,7 @@
NumberSeq* summary) {
int index;
juint* compact_table = p;
- // Find the start of the buckets, skip the compact_bucket_infos table
+ // Compute the start of the buckets, include the compact_bucket_infos table
// and the table end offset.
juint offset = _num_buckets + 1;
*first_bucket = compact_table + offset;
@@ -130,10 +131,17 @@
// Write the compact table's entries
juint* CompactHashtableWriter::dump_buckets(juint* compact_table, juint* p,
NumberSeq* summary) {
- uintx base_address = uintx(MetaspaceShared::shared_rs()->base());
- uintx max_delta = uintx(MetaspaceShared::shared_rs()->size());
- assert(max_delta <= 0x7fffffff, "range check");
+ uintx base_address = 0;
+ uintx max_delta = 0;
int num_compact_buckets = 0;
+ if (_type == CompactHashtable<Symbol*, char>::_symbol_table) {
+ base_address = uintx(MetaspaceShared::shared_rs()->base());
+ max_delta = uintx(MetaspaceShared::shared_rs()->size());
+ assert(max_delta <= 0x7fffffff, "range check");
+ } else {
+ assert((_type == CompactHashtable<oop, char>::_string_table), "unknown table");
+ assert(UseCompressedOops, "UseCompressedOops is required");
+ }
assert(p != NULL, "sanity");
for (int index = 0; index < _num_buckets; index++) {
@@ -148,12 +156,16 @@
for (Entry* tent = _buckets[index]; tent;
tent = tent->next()) {
if (bucket_type == REGULAR_BUCKET_TYPE) {
- *p++ = juint(tent->hash()); // write symbol hash
+ *p++ = juint(tent->hash()); // write entry hash
}
- uintx deltax = uintx(tent->value()) - base_address;
- assert(deltax < max_delta, "range check");
- juint delta = juint(deltax);
- *p++ = delta; // write symbol offset
+ if (_type == CompactHashtable<Symbol*, char>::_symbol_table) {
+ uintx deltax = uintx(tent->value()) - base_address;
+ assert(deltax < max_delta, "range check");
+ juint delta = juint(deltax);
+ *p++ = delta; // write entry offset
+ } else {
+ *p++ = oopDesc::encode_heap_oop(tent->string());
+ }
count ++;
}
assert(count == _bucket_sizes[index], "sanity");
@@ -174,6 +186,10 @@
uintx base_address = uintx(MetaspaceShared::shared_rs()->base());
+ // Now write the following at the beginning of the table:
+ // base_address (uintx)
+ // num_entries (juint)
+ // num_buckets (juint)
*p++ = high(base_address);
*p++ = low (base_address); // base address
*p++ = _num_entries; // number of entries in the table
@@ -191,7 +207,8 @@
if (_num_entries > 0) {
avg_cost = double(_required_bytes)/double(_num_entries);
}
- tty->print_cr("Shared %s table stats -------- base: " PTR_FORMAT, _table_name, (intptr_t)base_address);
+ tty->print_cr("Shared %s table stats -------- base: " PTR_FORMAT,
+ table_name(), (intptr_t)base_address);
tty->print_cr("Number of entries : %9d", _num_entries);
tty->print_cr("Total bytes used : %9d", (int)((*top) - old_top));
tty->print_cr("Average bytes per entry : %9.3f", avg_cost);
@@ -202,12 +219,24 @@
}
}
+const char* CompactHashtableWriter::table_name() {
+ switch (_type) {
+ case CompactHashtable<Symbol*, char>::_symbol_table: return "symbol";
+ case CompactHashtable<oop, char>::_string_table: return "string";
+ default:
+ ;
+ }
+ return "unknown";
+}
+
/////////////////////////////////////////////////////////////
//
// The CompactHashtable implementation
//
-template <class T, class N> const char* CompactHashtable<T, N>::init(const char* buffer) {
+template <class T, class N> const char* CompactHashtable<T, N>::init(
+ CompactHashtableType type, const char* buffer) {
assert(!DumpSharedSpaces, "run-time only");
+ _type = type;
juint*p = (juint*)buffer;
juint upper = *p++;
juint lower = *p++;
@@ -245,8 +274,34 @@
}
}
+template <class T, class N> void CompactHashtable<T, N>::oops_do(OopClosure* f) {
+ assert(!DumpSharedSpaces, "run-time only");
+ assert(_type == _string_table || _bucket_count == 0, "sanity");
+ for (juint i = 0; i < _bucket_count; i ++) {
+ juint bucket_info = _buckets[i];
+ juint bucket_offset = BUCKET_OFFSET(bucket_info);
+ int bucket_type = BUCKET_TYPE(bucket_info);
+ juint* bucket = _buckets + bucket_offset;
+ juint* bucket_end = _buckets;
+
+ narrowOop o;
+ if (bucket_type == COMPACT_BUCKET_TYPE) {
+ o = (narrowOop)bucket[0];
+ f->do_oop(&o);
+ } else {
+ bucket_end += BUCKET_OFFSET(_buckets[i + 1]);
+ while (bucket < bucket_end) {
+ o = (narrowOop)bucket[1];
+ f->do_oop(&o);
+ bucket += 2;
+ }
+ }
+ }
+}
+
// Explicitly instantiate these types
template class CompactHashtable<Symbol*, char>;
+template class CompactHashtable<oop, char>;
#ifndef O_BINARY // if defined (Win32) use binary files.
#define O_BINARY 0 // otherwise do nothing.
@@ -273,6 +328,8 @@
_p = _base;
_end = _base + st.st_size;
_filename = filename;
+ _prefix_type = Unknown;
+ _line_no = 1;
}
HashtableTextDump::~HashtableTextDump() {
@@ -286,9 +343,11 @@
vm_exit_during_initialization(err, msg);
}
-void HashtableTextDump::corrupted(const char *p) {
- char info[60];
- sprintf(info, "corrupted at pos %d", (int)(p - _base));
+void HashtableTextDump::corrupted(const char *p, const char* msg) {
+ char info[100];
+ jio_snprintf(info, sizeof(info),
+ "%s. Corrupted at line %d (file pos %d)",
+ msg, _line_no, (int)(p - _base));
quit(info, _filename);
}
@@ -298,8 +357,9 @@
} else if (_p[0] == '\n') {
_p += 1;
} else {
- corrupted(_p);
+ corrupted(_p, "Unexpected character");
}
+ _line_no ++;
return true;
}
@@ -328,26 +388,60 @@
skip_newline();
}
+void HashtableTextDump::scan_prefix_type() {
+ _p ++;
+ if (strncmp(_p, "SECTION: String", 15) == 0) {
+ _p += 15;
+ _prefix_type = StringPrefix;
+ } else if (strncmp(_p, "SECTION: Symbol", 15) == 0) {
+ _p += 15;
+ _prefix_type = SymbolPrefix;
+ } else {
+ _prefix_type = Unknown;
+ }
+ skip_newline();
+}
-int HashtableTextDump::scan_prefix() {
+int HashtableTextDump::scan_prefix(int* utf8_length) {
+ if (*_p == '@') {
+ scan_prefix_type();
+ }
+
+ switch (_prefix_type) {
+ case SymbolPrefix:
+ *utf8_length = scan_symbol_prefix(); break;
+ case StringPrefix:
+ *utf8_length = scan_string_prefix(); break;
+ default:
+ tty->print_cr("Shared input data type: Unknown.");
+ corrupted(_p, "Unknown data type");
+ }
+
+ return _prefix_type;
+}
+
+int HashtableTextDump::scan_string_prefix() {
// Expect /[0-9]+: /
- int utf8_length = get_num(':');
+ int utf8_length;
+ get_num(':', &utf8_length);
if (*_p != ' ') {
- corrupted(_p);
+ corrupted(_p, "Wrong prefix format for string");
}
_p++;
return utf8_length;
}
-int HashtableTextDump::scan_prefix2() {
+int HashtableTextDump::scan_symbol_prefix() {
// Expect /[0-9]+ (-|)[0-9]+: /
- int utf8_length = get_num(' ');
- if (*_p == '-') {
- _p++;
+ int utf8_length;
+ get_num(' ', &utf8_length);
+ if (*_p == '-') {
+ _p++;
}
- (void)get_num(':');
+ int ref_num;
+ (void)get_num(':', &ref_num);
if (*_p != ' ') {
- corrupted(_p);
+ corrupted(_p, "Wrong prefix format for symbol");
}
_p++;
return utf8_length;
@@ -408,7 +502,7 @@
case 'r': *to++ = '\r'; break;
case '\\': *to++ = '\\'; break;
default:
- ShouldNotReachHere();
+ corrupted(_p, "Unsupported character");
}
}
}
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -28,6 +28,7 @@
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "memory/allocation.inline.hpp"
+#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "services/diagnosticCommand.hpp"
#include "utilities/hashtable.hpp"
@@ -49,7 +50,7 @@
// the compact table to the shared archive.
//
// At dump time, the CompactHashtableWriter obtains all entries from the
-// symbol table and adds them to a new temporary hash table. The hash
+// symbol/string table and adds them to a new temporary hash table. The hash
// table size (number of buckets) is calculated using
// '(num_entries + bucket_size - 1) / bucket_size'. The default bucket
// size is 4 and can be changed by -XX:SharedSymbolTableBucketSize option.
@@ -57,14 +58,14 @@
// faster lookup. It also has relatively small number of empty buckets and
// good distribution of the entries.
//
-// We use a simple hash function (symbol_hash % num_bucket) for the table.
+// We use a simple hash function (hash % num_bucket) for the table.
// The new table is compacted when written out. Please see comments
// above the CompactHashtable class for the table layout detail. The bucket
// offsets are written to the archive as part of the compact table. The
// bucket offset is encoded in the low 30-bit (0-29) and the bucket type
// (regular or compact) are encoded in bit[31, 30]. For buckets with more
-// than one entry, both symbol hash and symbol offset are written to the
-// table. For buckets with only one entry, only the symbol offset is written
+// than one entry, both hash and entry offset are written to the
+// table. For buckets with only one entry, only the entry offset is written
// to the table and the buckets are tagged as compact in their type bits.
// Buckets without entry are skipped from the table. Their offsets are
// still written out for faster lookup.
@@ -78,6 +79,7 @@
public:
Entry(unsigned int hash, Symbol *symbol) : _next(NULL), _hash(hash), _literal(symbol) {}
+ Entry(unsigned int hash, oop string) : _next(NULL), _hash(hash), _literal(string) {}
void *value() {
return _literal;
@@ -85,6 +87,9 @@
Symbol *symbol() {
return (Symbol*)_literal;
}
+ oop string() {
+ return (oop)_literal;
+ }
unsigned int hash() {
return _hash;
}
@@ -95,7 +100,7 @@
private:
static int number_of_buckets(int num_entries);
- const char* _table_name;
+ int _type;
int _num_entries;
int _num_buckets;
juint* _bucket_sizes;
@@ -105,7 +110,7 @@
public:
// This is called at dump-time only
- CompactHashtableWriter(const char* table_name, int num_entries, CompactHashtableStats* stats);
+ CompactHashtableWriter(int table_type, int num_entries, CompactHashtableStats* stats);
~CompactHashtableWriter();
int get_required_bytes() {
@@ -116,6 +121,10 @@
add(hash, new Entry(hash, symbol));
}
+ void add(unsigned int hash, oop string) {
+ add(hash, new Entry(hash, string));
+ }
+
private:
void add(unsigned int hash, Entry* entry);
juint* dump_table(juint* p, juint** first_bucket, NumberSeq* summary);
@@ -123,6 +132,7 @@
public:
void dump(char** top, char* end);
+ const char* table_name();
};
#define REGULAR_BUCKET_TYPE 0
@@ -136,23 +146,23 @@
/////////////////////////////////////////////////////////////////////////////
//
-// CompactHashtable is used to stored the CDS archive's symbol table. Used
+// CompactHashtable is used to stored the CDS archive's symbol/string table. Used
// at runtime only to access the compact table from the archive.
//
// Because these tables are read-only (no entries can be added/deleted) at run-time
// and tend to have large number of entries, we try to minimize the footprint
// cost per entry.
//
-// Layout of compact symbol table in the shared archive:
+// Layout of compact table in the shared archive:
//
// uintx base_address;
-// juint num_symbols;
+// juint num_entries;
// juint num_buckets;
// juint bucket_infos[num_buckets+1]; // bit[31,30]: type; bit[29-0]: offset
// juint table[]
//
// -----------------------------------
-// | base_address | num_symbols |
+// | base_address | num_entries |
// |---------------------------------|
// | num_buckets | bucket_info0 |
// |---------------------------------|
@@ -177,9 +187,13 @@
// compact buckets have '01' in their highest 2-bit, and regular buckets have
// '00' in their highest 2-bit.
//
-// For normal buckets, each symbol's entry is 8 bytes in the table[]:
-// juint hash; /* symbol hash */
-// juint offset; /* Symbol* sym = (Symbol*)(base_address + offset) */
+// For normal buckets, each entry is 8 bytes in the table[]:
+// juint hash; /* symbol/string hash */
+// union {
+// juint offset; /* Symbol* sym = (Symbol*)(base_address + offset) */
+// narrowOop str; /* String narrowOop encoding */
+// }
+//
//
// For compact buckets, each entry has only the 4-byte 'offset' in the table[].
//
@@ -189,19 +203,41 @@
//
template <class T, class N> class CompactHashtable VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
+
+ public:
+ enum CompactHashtableType {
+ _symbol_table = 0,
+ _string_table = 1
+ };
+
+private:
+ CompactHashtableType _type;
uintx _base_address;
juint _entry_count;
juint _bucket_count;
juint _table_end_offset;
juint* _buckets;
- inline bool equals(T entry, const char* name, int len) {
- if (entry->equals(name, len)) {
- assert(entry->refcount() == -1, "must be shared");
- return true;
- } else {
- return false;
+ inline Symbol* lookup_entry(CompactHashtable<Symbol*, char>* const t,
+ juint* addr, const char* name, int len) {
+ Symbol* sym = (Symbol*)((void*)(_base_address + *addr));
+ if (sym->equals(name, len)) {
+ assert(sym->refcount() == -1, "must be shared");
+ return sym;
}
+
+ return NULL;
+ }
+
+ inline oop lookup_entry(CompactHashtable<oop, char>* const t,
+ juint* addr, const char* name, int len) {
+ narrowOop obj = (narrowOop)(*addr);
+ oop string = oopDesc::decode_heap_oop(obj);
+ if (java_lang_String::equals(string, (jchar*)name, len)) {
+ return string;
+ }
+
+ return NULL;
}
public:
@@ -211,7 +247,14 @@
_table_end_offset = 0;
_buckets = 0;
}
- const char* init(const char *buffer);
+ const char* init(CompactHashtableType type, const char *buffer);
+
+ void reset() {
+ _entry_count = 0;
+ _bucket_count = 0;
+ _table_end_offset = 0;
+ _buckets = 0;
+ }
// Lookup an entry from the compact table
inline T lookup(const N* name, unsigned int hash, int len) {
@@ -225,23 +268,22 @@
juint* bucket_end = _buckets;
if (bucket_type == COMPACT_BUCKET_TYPE) {
- // the compact bucket has one entry with symbol offset only
- T entry = (T)((void*)(_base_address + bucket[0]));
- if (equals(entry, name, len)) {
- return entry;
+ // the compact bucket has one entry with entry offset only
+ T res = lookup_entry(this, &bucket[0], name, len);
+ if (res != NULL) {
+ return res;
}
} else {
// This is a regular bucket, which has more than one
- // entries. Each entry is a pair of symbol (hash, offset).
+ // entries. Each entry is a pair of entry (hash, offset).
// Seek until the end of the bucket.
bucket_end += BUCKET_OFFSET(_buckets[index + 1]);
while (bucket < bucket_end) {
unsigned int h = (unsigned int)(bucket[0]);
if (h == hash) {
- juint offset = bucket[1];
- T entry = (T)((void*)(_base_address + offset));
- if (equals(entry, name, len)) {
- return entry;
+ T res = lookup_entry(this, &bucket[1], name, len);
+ if (res != NULL) {
+ return res;
}
}
bucket += 2;
@@ -253,12 +295,15 @@
// iterate over symbols
void symbols_do(SymbolClosure *cl);
+
+ // iterate over strings
+ void oops_do(OopClosure* f);
};
////////////////////////////////////////////////////////////////////////
//
// Read/Write the contents of a hashtable textual dump (created by
-// SymbolTable::dump).
+// SymbolTable::dump and StringTable::dump).
// Because the dump file may be big (hundred of MB in extreme cases),
// we use mmap for fast access when reading it.
//
@@ -269,21 +314,29 @@
const char* _end;
const char* _filename;
size_t _size;
+ int _prefix_type;
+ int _line_no;
public:
HashtableTextDump(const char* filename);
~HashtableTextDump();
+ enum {
+ SymbolPrefix = 1 << 0,
+ StringPrefix = 1 << 1,
+ Unknown = 1 << 2
+ };
+
void quit(const char* err, const char* msg);
inline int remain() {
return (int)(_end - _p);
}
- void corrupted(const char *p);
+ void corrupted(const char *p, const char *msg);
inline void corrupted_if(bool cond) {
if (cond) {
- corrupted(_p);
+ corrupted(_p, NULL);
}
}
@@ -292,7 +345,7 @@
void skip_past(char c);
void check_version(const char* ver);
- inline int get_num(char delim) {
+ inline bool get_num(char delim, int *utf8_length) {
const char* p = _p;
const char* end = _end;
int num = 0;
@@ -303,18 +356,22 @@
num = num * 10 + (c - '0');
} else if (c == delim) {
_p = p;
- return num;
+ *utf8_length = num;
+ return true;
} else {
- corrupted(p-1);
+ // Not [0-9], not 'delim'
+ return false;
}
}
- corrupted(_end);
+ corrupted(_end, "Incorrect format");
ShouldNotReachHere();
- return 0;
+ return false;
}
- int scan_prefix();
- int scan_prefix2();
+ void scan_prefix_type();
+ int scan_prefix(int* utf8_length);
+ int scan_string_prefix();
+ int scan_symbol_prefix();
jchar unescape(const char* from, const char* end, int count);
void get_utf8(char* utf8_buffer, int utf8_length);
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -118,6 +118,10 @@
return hash_offset;
}
+ static void set_value_raw(oop string, typeArrayOop buffer) {
+ assert(initialized, "Must be initialized");
+ string->obj_field_put_raw(value_offset, buffer);
+ }
static void set_value(oop string, typeArrayOop buffer) {
assert(initialized && (value_offset > 0), "Must be initialized");
string->obj_field_put(value_offset, (oop)buffer);
@@ -210,6 +214,7 @@
// Debugging
static void print(oop java_string, outputStream* st);
friend class JavaClasses;
+ friend class StringTable;
};
--- a/hotspot/src/share/vm/classfile/stringTable.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -38,6 +38,7 @@
#include "utilities/hashtable.inline.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
+#include "gc/g1/g1CollectedHeap.hpp"
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
#include "gc/g1/g1StringDedup.hpp"
#endif
@@ -87,19 +88,28 @@
// --------------------------------------------------------------------------
StringTable* StringTable::_the_table = NULL;
-
+bool StringTable::_ignore_shared_strings = false;
bool StringTable::_needs_rehashing = false;
volatile int StringTable::_parallel_claimed_idx = 0;
+CompactHashtable<oop, char> StringTable::_shared_table;
+
// Pick hashing algorithm
unsigned int StringTable::hash_string(const jchar* s, int len) {
return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) :
java_lang_String::hash_code(s, len);
}
-oop StringTable::lookup(int index, jchar* name,
- int len, unsigned int hash) {
+oop StringTable::lookup_shared(jchar* name, int len) {
+ // java_lang_String::hash_code() was used to compute hash values in the shared table. Don't
+ // use the hash value from StringTable::hash_string() as it might use alternate hashcode.
+ return _shared_table.lookup((const char*)name,
+ java_lang_String::hash_code(name, len), len);
+}
+
+oop StringTable::lookup_in_main_table(int index, jchar* name,
+ int len, unsigned int hash) {
int count = 0;
for (HashtableEntry<oop, mtSymbol>* l = bucket(index); l != NULL; l = l->next()) {
count++;
@@ -140,7 +150,8 @@
// Since look-up was done lock-free, we need to check if another
// thread beat us in the race to insert the symbol.
- oop test = lookup(index, name, len, hashValue); // calls lookup(u1*, int)
+ // No need to lookup the shared table from here since the caller (intern()) already did
+ oop test = lookup_in_main_table(index, name, len, hashValue); // calls lookup(u1*, int)
if (test != NULL) {
// Entry already added
return test;
@@ -172,9 +183,14 @@
}
oop StringTable::lookup(jchar* name, int len) {
+ oop string = lookup_shared(name, len);
+ if (string != NULL) {
+ return string;
+ }
+
unsigned int hash = hash_string(name, len);
int index = the_table()->hash_to_index(hash);
- oop string = the_table()->lookup(index, name, len, hash);
+ string = the_table()->lookup_in_main_table(index, name, len, hash);
ensure_string_alive(string);
@@ -184,9 +200,14 @@
oop StringTable::intern(Handle string_or_null, jchar* name,
int len, TRAPS) {
+ oop found_string = lookup_shared(name, len);
+ if (found_string != NULL) {
+ return found_string;
+ }
+
unsigned int hashValue = hash_string(name, len);
int index = the_table()->hash_to_index(hashValue);
- oop found_string = the_table()->lookup(index, name, len, hashValue);
+ found_string = the_table()->lookup_in_main_table(index, name, len, hashValue);
// Found
if (found_string != NULL) {
@@ -611,3 +632,131 @@
return 0;
}
}
+
+// Sharing
+bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
+ CompactHashtableWriter* ch_table) {
+#if INCLUDE_CDS && INCLUDE_ALL_GCS && defined(_LP64) && !defined(_WINDOWS)
+ assert(UseG1GC, "Only support G1 GC");
+ assert(UseCompressedOops && UseCompressedClassPointers,
+ "Only support UseCompressedOops and UseCompressedClassPointers enabled");
+
+ Thread* THREAD = Thread::current();
+ G1CollectedHeap::heap()->begin_archive_alloc_range();
+ for (int i = 0; i < the_table()->table_size(); ++i) {
+ HashtableEntry<oop, mtSymbol>* bucket = the_table()->bucket(i);
+ for ( ; bucket != NULL; bucket = bucket->next()) {
+ oop s = bucket->literal();
+ unsigned int hash = java_lang_String::hash_code(s);
+ if (hash == 0) {
+ continue;
+ }
+
+ // allocate the new 'value' array first
+ typeArrayOop v = java_lang_String::value(s);
+ int v_len = v->size();
+ typeArrayOop new_v;
+ if (G1CollectedHeap::heap()->is_archive_alloc_too_large(v_len)) {
+ continue; // skip the current String. The 'value' array is too large to handle
+ } else {
+ new_v = (typeArrayOop)G1CollectedHeap::heap()->archive_mem_allocate(v_len);
+ if (new_v == NULL) {
+ return false; // allocation failed
+ }
+ }
+ // now allocate the new String object
+ int s_len = s->size();
+ oop new_s = (oop)G1CollectedHeap::heap()->archive_mem_allocate(s_len);
+ if (new_s == NULL) {
+ return false;
+ }
+
+ s->identity_hash();
+ v->identity_hash();
+
+ // copy the objects' data
+ Copy::aligned_disjoint_words((HeapWord*)s, (HeapWord*)new_s, s_len);
+ Copy::aligned_disjoint_words((HeapWord*)v, (HeapWord*)new_v, v_len);
+
+ // adjust the pointer to the 'value' field in the new String oop. Also pre-compute and set the
+ // 'hash' field. That avoids "write" to the shared strings at runtime by the deduplication process.
+ java_lang_String::set_value_raw(new_s, new_v);
+ if (java_lang_String::hash(new_s) == 0) {
+ java_lang_String::set_hash(new_s, hash);
+ }
+
+ // add to the compact table
+ ch_table->add(hash, new_s);
+ }
+ }
+
+ G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity());
+ assert(string_space->length() <= 2, "sanity");
+#endif
+ return true;
+}
+
+bool StringTable::copy_compact_table(char** top, char *end, GrowableArray<MemRegion> *string_space,
+ size_t* space_size) {
+#if INCLUDE_CDS && defined(_LP64) && !defined(_WINDOWS)
+ if (!(UseG1GC && UseCompressedOops && UseCompressedClassPointers)) {
+ if (PrintSharedSpaces) {
+ tty->print_cr("Shared strings are excluded from the archive as UseG1GC, "
+ "UseCompressedOops and UseCompressedClassPointers are required.");
+ }
+ return true;
+ }
+
+ CompactHashtableWriter ch_table(CompactHashtable<oop, char>::_string_table,
+ the_table()->number_of_entries(),
+ &MetaspaceShared::stats()->string);
+
+ // Copy the interned strings into the "string space" within the java heap
+ if (!copy_shared_string(string_space, &ch_table)) {
+ return false;
+ }
+
+ for (int i = 0; i < string_space->length(); i++) {
+ *space_size += string_space->at(i).byte_size();
+ }
+
+ // Now dump the compact table
+ if (*top + ch_table.get_required_bytes() > end) {
+ // not enough space left
+ return false;
+ }
+ ch_table.dump(top, end);
+ *top = (char*)align_pointer_up(*top, sizeof(void*));
+
+#endif
+ return true;
+}
+
+void StringTable::shared_oops_do(OopClosure* f) {
+#if INCLUDE_CDS && defined(_LP64) && !defined(_WINDOWS)
+ _shared_table.oops_do(f);
+#endif
+}
+
+const char* StringTable::init_shared_table(FileMapInfo *mapinfo, char *buffer) {
+#if INCLUDE_CDS && defined(_LP64) && !defined(_WINDOWS)
+ if (mapinfo->space_capacity(MetaspaceShared::first_string) == 0) {
+ // no shared string data
+ return buffer;
+ }
+
+ // initialize the shared table
+ juint *p = (juint*)buffer;
+ const char* end = _shared_table.init(
+ CompactHashtable<oop, char>::_string_table, (char*)p);
+ const char* aligned_end = (const char*)align_pointer_up(end, sizeof(void*));
+
+ if (_ignore_shared_strings) {
+ _shared_table.reset();
+ }
+
+ return aligned_end;
+#endif
+
+ return buffer;
+}
--- a/hotspot/src/share/vm/classfile/stringTable.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/classfile/stringTable.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,10 @@
#include "memory/allocation.inline.hpp"
#include "utilities/hashtable.hpp"
+template <class T, class N> class CompactHashtable;
+class CompactHashtableWriter;
+class FileMapInfo;
+
class StringTable : public RehashableHashtable<oop, mtSymbol> {
friend class VMStructs;
friend class Symbol;
@@ -36,6 +40,10 @@
// The string table
static StringTable* _the_table;
+ // Shared string table
+ static CompactHashtable<oop, char> _shared_table;
+ static bool _ignore_shared_strings;
+
// Set if one bucket is out of balance due to hash algorithm deficiency
static bool _needs_rehashing;
@@ -46,7 +54,8 @@
oop basic_add(int index, Handle string_or_null, jchar* name, int len,
unsigned int hashValue, TRAPS);
- oop lookup(int index, jchar* chars, int length, unsigned int hashValue);
+ oop lookup_in_main_table(int index, jchar* chars, int length, unsigned int hashValue);
+ static oop lookup_shared(jchar* name, int len);
// Apply the give oop closure to the entries to the buckets
// in the range [start_idx, end_idx).
@@ -141,12 +150,14 @@
static int verify_and_compare_entries();
// Sharing
- static void copy_buckets(char** top, char*end) {
- the_table()->Hashtable<oop, mtSymbol>::copy_buckets(top, end);
- }
- static void copy_table(char** top, char*end) {
- the_table()->Hashtable<oop, mtSymbol>::copy_table(top, end);
- }
+ static void ignore_shared_strings(bool v) { _ignore_shared_strings = v; }
+ static bool shared_string_ignored() { return _ignore_shared_strings; }
+ static void shared_oops_do(OopClosure* f);
+ static bool copy_shared_string(GrowableArray<MemRegion> *string_space,
+ CompactHashtableWriter* ch_table);
+ static bool copy_compact_table(char** top, char* end, GrowableArray<MemRegion> *string_space,
+ size_t* space_size);
+ static const char* init_shared_table(FileMapInfo *mapinfo, char* buffer);
static void reverse() {
the_table()->Hashtable<oop, mtSymbol>::reverse();
}
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -539,7 +539,8 @@
bool SymbolTable::copy_compact_table(char** top, char*end) {
#if INCLUDE_CDS
- CompactHashtableWriter ch_table("symbol", the_table()->number_of_entries(),
+ CompactHashtableWriter ch_table(CompactHashtable<Symbol*, char>::_symbol_table,
+ the_table()->number_of_entries(),
&MetaspaceShared::stats()->symbol);
if (*top + ch_table.get_required_bytes() > end) {
// not enough space left
@@ -556,7 +557,6 @@
}
}
- char* old_top = *top;
ch_table.dump(top, end);
*top = (char*)align_pointer_up(*top, sizeof(void*));
@@ -565,7 +565,8 @@
}
const char* SymbolTable::init_shared_table(const char* buffer) {
- const char* end = _shared_table.init(buffer);
+ const char* end = _shared_table.init(
+ CompactHashtable<Symbol*, char>::_symbol_table, buffer);
return (const char*)align_pointer_up(end, sizeof(void*));
}
--- a/hotspot/src/share/vm/code/codeCache.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/code/codeCache.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -190,7 +190,12 @@
static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; }
static void clear_inline_caches(); // clear all inline caches
- // Returns the CodeBlobType for nmethods of the given compilation level
+ // Returns the CodeBlobType for the given nmethod
+ static int get_code_blob_type(nmethod* nm) {
+ return get_code_heap(nm)->code_blob_type();
+ }
+
+ // Returns the CodeBlobType for the given compilation level
static int get_code_blob_type(int comp_level) {
if (comp_level == CompLevel_none ||
comp_level == CompLevel_simple ||
@@ -287,7 +292,7 @@
// Iterate over all CodeBlobs
_code_blob_type = CodeBlobType::All;
} else if (nm != NULL) {
- _code_blob_type = CodeCache::get_code_blob_type(nm->comp_level());
+ _code_blob_type = CodeCache::get_code_blob_type(nm);
} else {
// Only iterate over method code heaps, starting with non-profiled
_code_blob_type = CodeBlobType::MethodNonProfiled;
--- a/hotspot/src/share/vm/code/nmethod.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/code/nmethod.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1421,7 +1421,7 @@
Events::log(JavaThread::current(), "flushing nmethod " INTPTR_FORMAT, this);
if (PrintMethodFlushing) {
tty->print_cr("*flushing nmethod %3d/" INTPTR_FORMAT ". Live blobs:" UINT32_FORMAT "/Free CodeCache:" SIZE_FORMAT "Kb",
- _compile_id, this, CodeCache::nof_blobs(), CodeCache::unallocated_capacity(CodeCache::get_code_blob_type(_comp_level))/1024);
+ _compile_id, this, CodeCache::nof_blobs(), CodeCache::unallocated_capacity(CodeCache::get_code_blob_type(this))/1024);
}
// We need to deallocate any ExceptionCache data.
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -190,10 +190,10 @@
};
ConcurrentMarkSweepGeneration::ConcurrentMarkSweepGeneration(
- ReservedSpace rs, size_t initial_byte_size, int level,
+ ReservedSpace rs, size_t initial_byte_size,
CardTableRS* ct, bool use_adaptive_freelists,
FreeBlockDictionary<FreeChunk>::DictionaryChoice dictionaryChoice) :
- CardGeneration(rs, initial_byte_size, level, ct),
+ CardGeneration(rs, initial_byte_size, ct),
_dilatation_factor(((double)MinChunkSize)/((double)(CollectedHeap::min_fill_size()))),
_did_compact(false)
{
@@ -285,9 +285,9 @@
_ref_processor =
new ReferenceProcessor(_span, // span
(ParallelGCThreads > 1) && ParallelRefProcEnabled, // mt processing
- (int) ParallelGCThreads, // mt processing degree
+ ParallelGCThreads, // mt processing degree
_cmsGen->refs_discovery_is_mt(), // mt discovery
- (int) MAX2(ConcGCThreads, ParallelGCThreads), // mt discovery degree
+ MAX2(ConcGCThreads, ParallelGCThreads), // mt discovery degree
_cmsGen->refs_discovery_is_atomic(), // discovery is not atomic
&_is_alive_closure); // closure for liveness info
// Initialize the _ref_processor field of CMSGen
@@ -562,7 +562,7 @@
// are not shared with parallel scavenge (ParNew).
{
uint i;
- uint num_queues = (uint) MAX2(ParallelGCThreads, ConcGCThreads);
+ uint num_queues = MAX2(ParallelGCThreads, ConcGCThreads);
if ((CMSParallelRemarkEnabled || CMSConcurrentMTEnabled
|| ParallelRefProcEnabled)
@@ -682,12 +682,17 @@
void ConcurrentMarkSweepGeneration::printOccupancy(const char *s) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
if (PrintGCDetails) {
+ // I didn't want to change the logging when removing the level concept,
+ // but I guess this logging could say "old" or something instead of "1".
+ assert(gch->is_old_gen(this),
+ "The CMS generation should be the old generation");
+ uint level = 1;
if (Verbose) {
- gclog_or_tty->print("[%d %s-%s: "SIZE_FORMAT"("SIZE_FORMAT")]",
- level(), short_name(), s, used(), capacity());
+ gclog_or_tty->print("[%u %s-%s: "SIZE_FORMAT"("SIZE_FORMAT")]",
+ level, short_name(), s, used(), capacity());
} else {
- gclog_or_tty->print("[%d %s-%s: "SIZE_FORMAT"K("SIZE_FORMAT"K)]",
- level(), short_name(), s, used() / K, capacity() / K);
+ gclog_or_tty->print("[%u %s-%s: "SIZE_FORMAT"K("SIZE_FORMAT"K)]",
+ level, short_name(), s, used() / K, capacity() / K);
}
}
if (Verbose) {
@@ -797,27 +802,22 @@
gclog_or_tty->print_cr("\nFrom compute_new_size: ");
gclog_or_tty->print_cr(" Free fraction %f", free_percentage);
gclog_or_tty->print_cr(" Desired free fraction %f",
- desired_free_percentage);
+ desired_free_percentage);
gclog_or_tty->print_cr(" Maximum free fraction %f",
- maximum_free_percentage);
+ maximum_free_percentage);
gclog_or_tty->print_cr(" Capacity "SIZE_FORMAT, capacity()/1000);
gclog_or_tty->print_cr(" Desired capacity "SIZE_FORMAT,
- desired_capacity/1000);
- int prev_level = level() - 1;
- if (prev_level >= 0) {
- size_t prev_size = 0;
- GenCollectedHeap* gch = GenCollectedHeap::heap();
- Generation* prev_gen = gch->young_gen();
- prev_size = prev_gen->capacity();
- gclog_or_tty->print_cr(" Younger gen size "SIZE_FORMAT,
- prev_size/1000);
- }
+ desired_capacity/1000);
+ GenCollectedHeap* gch = GenCollectedHeap::heap();
+ assert(gch->is_old_gen(this), "The CMS generation should always be the old generation");
+ size_t young_size = gch->young_gen()->capacity();
+ gclog_or_tty->print_cr(" Young gen size " SIZE_FORMAT, young_size / 1000);
gclog_or_tty->print_cr(" unsafe_max_alloc_nogc "SIZE_FORMAT,
- unsafe_max_alloc_nogc()/1000);
+ unsafe_max_alloc_nogc()/1000);
gclog_or_tty->print_cr(" contiguous available "SIZE_FORMAT,
- contiguous_available()/1000);
+ contiguous_available()/1000);
gclog_or_tty->print_cr(" Expand by "SIZE_FORMAT" (bytes)",
- expand_bytes);
+ expand_bytes);
}
// safe if expansion fails
expand_for_gc_cause(expand_bytes, 0, CMSExpansionCause::_satisfy_free_ratio);
@@ -1650,8 +1650,7 @@
_intra_sweep_estimate.padded_average());
}
- GenMarkSweep::invoke_at_safepoint(_cmsGen->level(),
- ref_processor(), clear_all_soft_refs);
+ GenMarkSweep::invoke_at_safepoint(ref_processor(), clear_all_soft_refs);
#ifdef ASSERT
CompactibleFreeListSpace* cms_space = _cmsGen->cmsSpace();
size_t free_size = cms_space->free();
@@ -2432,7 +2431,7 @@
StrongRootsScope srs(1);
gch->gen_process_roots(&srs,
- _cmsGen->level(),
+ GenCollectedHeap::OldGen,
true, // younger gens are roots
GenCollectedHeap::ScanningOption(roots_scanning_options()),
should_unload_classes(),
@@ -2504,7 +2503,7 @@
StrongRootsScope srs(1);
gch->gen_process_roots(&srs,
- _cmsGen->level(),
+ GenCollectedHeap::OldGen,
true, // younger gens are roots
GenCollectedHeap::ScanningOption(roots_scanning_options()),
should_unload_classes(),
@@ -3031,7 +3030,7 @@
StrongRootsScope srs(1);
gch->gen_process_roots(&srs,
- _cmsGen->level(),
+ GenCollectedHeap::OldGen,
true, // younger gens are roots
GenCollectedHeap::ScanningOption(roots_scanning_options()),
should_unload_classes(),
@@ -4282,15 +4281,12 @@
FlagSetting fl(gch->_is_gc_active, false);
NOT_PRODUCT(GCTraceTime t("Scavenge-Before-Remark",
PrintGCDetails && Verbose, true, _gc_timer_cm, _gc_tracer_cm->gc_id());)
- int level = _cmsGen->level() - 1;
- if (level >= 0) {
- gch->do_collection(true, // full (i.e. force, see below)
- false, // !clear_all_soft_refs
- 0, // size
- false, // is_tlab
- level // max_level
- );
- }
+ gch->do_collection(true, // full (i.e. force, see below)
+ false, // !clear_all_soft_refs
+ 0, // size
+ false, // is_tlab
+ GenCollectedHeap::YoungGen // type
+ );
}
FreelistLocker x(this);
MutexLockerEx y(bitMapLock(),
@@ -4464,7 +4460,7 @@
CLDToOopClosure cld_closure(&par_mri_cl, true);
gch->gen_process_roots(_strong_roots_scope,
- _collector->_cmsGen->level(),
+ GenCollectedHeap::OldGen,
false, // yg was scanned above
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
_collector->should_unload_classes(),
@@ -4603,7 +4599,7 @@
_timer.reset();
_timer.start();
gch->gen_process_roots(_strong_roots_scope,
- _collector->_cmsGen->level(),
+ GenCollectedHeap::OldGen,
false, // yg was scanned above
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
_collector->should_unload_classes(),
@@ -5184,7 +5180,7 @@
StrongRootsScope srs(1);
gch->gen_process_roots(&srs,
- _cmsGen->level(),
+ GenCollectedHeap::OldGen,
true, // younger gens as roots
GenCollectedHeap::ScanningOption(roots_scanning_options()),
should_unload_classes(),
@@ -5322,8 +5318,8 @@
_bit_map(bit_map),
_work_queue(work_queue),
_mark_and_push(collector, span, bit_map, work_queue),
- _low_water_mark(MIN2((uint)(work_queue->max_elems()/4),
- (uint)(CMSWorkQueueDrainThreshold * ParallelGCThreads)))
+ _low_water_mark(MIN2((work_queue->max_elems()/4),
+ ((uint)CMSWorkQueueDrainThreshold * ParallelGCThreads)))
{ }
// . see if we can share work_queues with ParNew? XXX
@@ -5648,11 +5644,12 @@
return _cmsSpace->find_chunk_at_end();
}
-void ConcurrentMarkSweepGeneration::update_gc_stats(int current_level,
+void ConcurrentMarkSweepGeneration::update_gc_stats(Generation* current_generation,
bool full) {
- // The next lower level has been collected. Gather any statistics
+ // If the young generation has been collected, gather any statistics
// that are of interest at this point.
- if (!full && (current_level + 1) == level()) {
+ bool current_is_young = GenCollectedHeap::heap()->is_young_gen(current_generation);
+ if (!full && current_is_young) {
// Gather statistics on the young generation collection.
collector()->stats().record_gc0_end(used());
}
@@ -6251,8 +6248,8 @@
_span(span),
_bit_map(bit_map),
_work_queue(work_queue),
- _low_water_mark(MIN2((uint)(work_queue->max_elems()/4),
- (uint)(CMSWorkQueueDrainThreshold * ParallelGCThreads))),
+ _low_water_mark(MIN2((work_queue->max_elems()/4),
+ ((uint)CMSWorkQueueDrainThreshold * ParallelGCThreads))),
_par_pushAndMarkClosure(collector, span, rp, bit_map, work_queue)
{
_ref_processor = rp;
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1063,7 +1063,7 @@
void shrink_free_list_by(size_t bytes);
// Update statistics for GC
- virtual void update_gc_stats(int level, bool full);
+ virtual void update_gc_stats(Generation* current_generation, bool full);
// Maximum available space in the generation (including uncommitted)
// space.
@@ -1079,7 +1079,7 @@
public:
ConcurrentMarkSweepGeneration(ReservedSpace rs, size_t initial_byte_size,
- int level, CardTableRS* ct,
+ CardTableRS* ct,
bool use_adaptive_freelists,
FreeBlockDictionary<FreeChunk>::DictionaryChoice);
--- a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -42,7 +42,7 @@
uint n_threads) {
assert(n_threads > 0, "expected n_threads > 0");
assert(n_threads <= ParallelGCThreads,
- err_msg("n_threads: %u > ParallelGCThreads: " UINTX_FORMAT, n_threads, ParallelGCThreads));
+ err_msg("n_threads: %u > ParallelGCThreads: %u", n_threads, ParallelGCThreads));
// Make sure the LNC array is valid for the space.
jbyte** lowest_non_clean;
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -62,25 +62,25 @@
#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
#endif
ParScanThreadState::ParScanThreadState(Space* to_space_,
- ParNewGeneration* gen_,
+ ParNewGeneration* young_gen_,
Generation* old_gen_,
int thread_num_,
ObjToScanQueueSet* work_queue_set_,
Stack<oop, mtGC>* overflow_stacks_,
size_t desired_plab_sz_,
ParallelTaskTerminator& term_) :
- _to_space(to_space_), _old_gen(old_gen_), _young_gen(gen_), _thread_num(thread_num_),
+ _to_space(to_space_), _old_gen(old_gen_), _young_gen(young_gen_), _thread_num(thread_num_),
_work_queue(work_queue_set_->queue(thread_num_)), _to_space_full(false),
_overflow_stack(overflow_stacks_ ? overflow_stacks_ + thread_num_ : NULL),
_ageTable(false), // false ==> not the global age table, no perf data.
_to_space_alloc_buffer(desired_plab_sz_),
- _to_space_closure(gen_, this), _old_gen_closure(gen_, this),
- _to_space_root_closure(gen_, this), _old_gen_root_closure(gen_, this),
- _older_gen_closure(gen_, this),
+ _to_space_closure(young_gen_, this), _old_gen_closure(young_gen_, this),
+ _to_space_root_closure(young_gen_, this), _old_gen_root_closure(young_gen_, this),
+ _older_gen_closure(young_gen_, this),
_evacuate_followers(this, &_to_space_closure, &_old_gen_closure,
- &_to_space_root_closure, gen_, &_old_gen_root_closure,
+ &_to_space_root_closure, young_gen_, &_old_gen_root_closure,
work_queue_set_, &term_),
- _is_alive_closure(gen_), _scan_weak_ref_closure(gen_, this),
+ _is_alive_closure(young_gen_), _scan_weak_ref_closure(young_gen_, this),
_keep_alive_closure(&_scan_weak_ref_closure),
_strong_roots_time(0.0), _term_time(0.0)
{
@@ -481,7 +481,6 @@
ParScanThreadState* par_scan_state) :
OopsInKlassOrGenClosure(g), _par_scan_state(par_scan_state), _g(g)
{
- assert(_g->level() == 0, "Optimized for youngest generation");
_boundary = _g->reserved().end();
}
@@ -566,11 +565,11 @@
par_scan_state()->end_term_time();
}
-ParNewGenTask::ParNewGenTask(ParNewGeneration* gen, Generation* old_gen,
+ParNewGenTask::ParNewGenTask(ParNewGeneration* young_gen, Generation* old_gen,
HeapWord* young_old_boundary, ParScanThreadStateSet* state_set,
StrongRootsScope* strong_roots_scope) :
AbstractGangTask("ParNewGeneration collection"),
- _gen(gen), _old_gen(old_gen),
+ _young_gen(young_gen), _old_gen(old_gen),
_young_old_boundary(young_old_boundary),
_state_set(state_set),
_strong_roots_scope(strong_roots_scope)
@@ -596,7 +595,7 @@
par_scan_state.start_strong_roots();
gch->gen_process_roots(_strong_roots_scope,
- _gen->level(),
+ GenCollectedHeap::YoungGen,
true, // Process younger gens, if any,
// as strong roots.
GenCollectedHeap::SO_ScavengeCodeCache,
@@ -616,8 +615,8 @@
#pragma warning( disable:4355 ) // 'this' : used in base member initializer list
#endif
ParNewGeneration::
-ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level)
- : DefNewGeneration(rs, initial_byte_size, level, "PCopy"),
+ParNewGeneration(ReservedSpace rs, size_t initial_byte_size)
+ : DefNewGeneration(rs, initial_byte_size, "PCopy"),
_overflow_list(NULL),
_is_alive_closure(this),
_plab_stats(YoungPLABSize, PLABWeight)
@@ -752,7 +751,7 @@
private:
virtual void work(uint worker_id);
private:
- ParNewGeneration& _gen;
+ ParNewGeneration& _young_gen;
ProcessTask& _task;
Generation& _old_gen;
HeapWord* _young_old_boundary;
@@ -760,12 +759,12 @@
};
ParNewRefProcTaskProxy::ParNewRefProcTaskProxy(ProcessTask& task,
- ParNewGeneration& gen,
+ ParNewGeneration& young_gen,
Generation& old_gen,
HeapWord* young_old_boundary,
ParScanThreadStateSet& state_set)
: AbstractGangTask("ParNewGeneration parallel reference processing"),
- _gen(gen),
+ _young_gen(young_gen),
_task(task),
_old_gen(old_gen),
_young_old_boundary(young_old_boundary),
@@ -806,12 +805,12 @@
GenCollectedHeap* gch = GenCollectedHeap::heap();
FlexibleWorkGang* workers = gch->workers();
assert(workers != NULL, "Need parallel worker threads.");
- _state_set.reset(workers->active_workers(), _generation.promotion_failed());
- ParNewRefProcTaskProxy rp_task(task, _generation, *_generation.next_gen(),
- _generation.reserved().end(), _state_set);
+ _state_set.reset(workers->active_workers(), _young_gen.promotion_failed());
+ ParNewRefProcTaskProxy rp_task(task, _young_gen, _old_gen,
+ _young_gen.reserved().end(), _state_set);
workers->run_task(&rp_task);
_state_set.reset(0 /* bad value in debug if not reset */,
- _generation.promotion_failed());
+ _young_gen.promotion_failed());
}
void ParNewRefProcTaskExecutor::execute(EnqueueTask& task)
@@ -835,10 +834,10 @@
ScanClosure(g, gc_barrier) {}
EvacuateFollowersClosureGeneral::
-EvacuateFollowersClosureGeneral(GenCollectedHeap* gch, int level,
+EvacuateFollowersClosureGeneral(GenCollectedHeap* gch,
OopsInGenClosure* cur,
OopsInGenClosure* older) :
- _gch(gch), _level(level),
+ _gch(gch),
_scan_cur_or_nonheap(cur), _scan_older(older)
{}
@@ -846,10 +845,10 @@
do {
// Beware: this call will lead to closure applications via virtual
// calls.
- _gch->oop_since_save_marks_iterate(_level,
+ _gch->oop_since_save_marks_iterate(GenCollectedHeap::YoungGen,
_scan_cur_or_nonheap,
_scan_older);
- } while (!_gch->no_allocs_since_save_marks(_level));
+ } while (!_gch->no_allocs_since_save_marks(true /* include_young */));
}
@@ -972,14 +971,14 @@
ScanClosure scan_without_gc_barrier(this, false);
ScanClosureWithParBarrier scan_with_gc_barrier(this, true);
set_promo_failure_scan_stack_closure(&scan_without_gc_barrier);
- EvacuateFollowersClosureGeneral evacuate_followers(gch, _level,
+ EvacuateFollowersClosureGeneral evacuate_followers(gch,
&scan_without_gc_barrier, &scan_with_gc_barrier);
rp->setup_policy(clear_all_soft_refs);
// Can the mt_degree be set later (at run_task() time would be best)?
rp->set_active_mt_degree(active_workers);
ReferenceProcessorStats stats;
if (rp->processing_is_mt()) {
- ParNewRefProcTaskExecutor task_executor(*this, thread_state_set);
+ ParNewRefProcTaskExecutor task_executor(*this, *_old_gen, thread_state_set);
stats = rp->process_discovered_references(&is_alive, &keep_alive,
&evacuate_followers, &task_executor,
_gc_timer, _gc_tracer.gc_id());
@@ -1045,7 +1044,7 @@
rp->set_enqueuing_is_done(true);
if (rp->processing_is_mt()) {
- ParNewRefProcTaskExecutor task_executor(*this, thread_state_set);
+ ParNewRefProcTaskExecutor task_executor(*this, *_old_gen, thread_state_set);
rp->enqueue_discovered_references(&task_executor);
} else {
rp->enqueue_discovered_references(NULL);
@@ -1349,7 +1348,7 @@
oop prefix = cast_to_oop(Atomic::xchg_ptr(BUSY, &_overflow_list));
// Trim off a prefix of at most objsFromOverflow items
Thread* tid = Thread::current();
- size_t spin_count = (size_t)ParallelGCThreads;
+ size_t spin_count = ParallelGCThreads;
size_t sleep_time_millis = MAX2((size_t)1, objsFromOverflow/100);
for (size_t spin = 0; prefix == BUSY && spin < spin_count; spin++) {
// someone grabbed it before we did ...
@@ -1466,9 +1465,9 @@
_ref_processor =
new ReferenceProcessor(_reserved, // span
ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing
- (uint) ParallelGCThreads, // mt processing degree
+ ParallelGCThreads, // mt processing degree
refs_discovery_is_mt(), // mt discovery
- (uint) ParallelGCThreads, // mt discovery degree
+ ParallelGCThreads, // mt discovery degree
refs_discovery_is_atomic(), // atomic_discovery
NULL); // is_alive_non_header
}
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -234,14 +234,14 @@
class ParNewGenTask: public AbstractGangTask {
private:
- ParNewGeneration* _gen;
+ ParNewGeneration* _young_gen;
Generation* _old_gen;
HeapWord* _young_old_boundary;
class ParScanThreadStateSet* _state_set;
StrongRootsScope* _strong_roots_scope;
public:
- ParNewGenTask(ParNewGeneration* gen,
+ ParNewGenTask(ParNewGeneration* young_gen,
Generation* old_gen,
HeapWord* young_old_boundary,
ParScanThreadStateSet* state_set,
@@ -264,11 +264,10 @@
class EvacuateFollowersClosureGeneral: public VoidClosure {
private:
GenCollectedHeap* _gch;
- int _level;
OopsInGenClosure* _scan_cur_or_nonheap;
OopsInGenClosure* _scan_older;
public:
- EvacuateFollowersClosureGeneral(GenCollectedHeap* gch, int level,
+ EvacuateFollowersClosureGeneral(GenCollectedHeap* gch,
OopsInGenClosure* cur,
OopsInGenClosure* older);
virtual void do_void();
@@ -288,12 +287,14 @@
// Implements AbstractRefProcTaskExecutor for ParNew.
class ParNewRefProcTaskExecutor: public AbstractRefProcTaskExecutor {
private:
- ParNewGeneration& _generation;
+ ParNewGeneration& _young_gen;
+ Generation& _old_gen;
ParScanThreadStateSet& _state_set;
public:
- ParNewRefProcTaskExecutor(ParNewGeneration& generation,
+ ParNewRefProcTaskExecutor(ParNewGeneration& young_gen,
+ Generation& old_gen,
ParScanThreadStateSet& state_set)
- : _generation(generation), _state_set(state_set)
+ : _young_gen(young_gen), _old_gen(old_gen), _state_set(state_set)
{ }
// Executes a task using worker threads.
@@ -353,7 +354,7 @@
void set_survivor_overflow(bool v) { _survivor_overflow = v; }
public:
- ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level);
+ ParNewGeneration(ReservedSpace rs, size_t initial_byte_size);
~ParNewGeneration() {
for (uint i = 0; i < ParallelGCThreads; i++)
--- a/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/cms/parOopClosures.inline.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -72,7 +72,7 @@
bool root_scan) {
assert((!GenCollectedHeap::heap()->is_in_reserved(p) ||
generation()->is_in_reserved(p))
- && (generation()->level() == 0 || gc_barrier),
+ && (GenCollectedHeap::heap()->is_young_gen(generation()) || gc_barrier),
"The gen must be right, and we must be doing the barrier "
"in older generations.");
T heap_oop = oopDesc::load_heap_oop(p);
--- a/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/cms/vmCMSOperations.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -198,8 +198,7 @@
assert(SafepointSynchronize::is_at_safepoint(),
"We can only be executing this arm of if at a safepoint");
GCCauseSetter gccs(gch, _gc_cause);
- gch->do_full_collection(gch->must_clear_all_soft_refs(),
- 0 /* collect only youngest gen */);
+ gch->do_full_collection(gch->must_clear_all_soft_refs(), GenCollectedHeap::YoungGen);
} // Else no need for a foreground young gc
assert((_gc_count_before < gch->total_collections()) ||
(GC_locker::is_active() /* gc may have been skipped */
--- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -107,7 +107,8 @@
HeapRegion *curr = regions_at(index++);
guarantee(curr != NULL, "Regions in _regions array cannot be NULL");
guarantee(!curr->is_young(), "should not be young!");
- guarantee(!curr->is_humongous(), "should not be humongous!");
+ guarantee(!curr->is_pinned(),
+ err_msg("Pinned region should not be in collection set (index %u)", curr->hrm_index()));
if (prev != NULL) {
guarantee(order_regions(prev, curr) != 1,
err_msg("GC eff prev: %1.4f GC eff curr: %1.4f",
@@ -149,8 +150,8 @@
void CollectionSetChooser::add_region(HeapRegion* hr) {
- assert(!hr->is_humongous(),
- "Humongous regions shouldn't be added to the collection set");
+ assert(!hr->is_pinned(),
+ err_msg("Pinned region shouldn't be added to the collection set (index %u)", hr->hrm_index()));
assert(!hr->is_young(), "should not be young!");
_regions.append(hr);
_length++;
--- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -103,13 +103,12 @@
void sort_regions();
// Determine whether to add the given region to the CSet chooser or
- // not. Currently, we skip humongous regions (we never add them to
- // the CSet, we only reclaim them during cleanup) and regions whose
- // live bytes are over the threshold.
+ // not. Currently, we skip pinned regions and regions whose live
+ // bytes are over the threshold. Humongous regions may be reclaimed during cleanup.
bool should_add(HeapRegion* hr) {
assert(hr->is_marked(), "pre-condition");
assert(!hr->is_young(), "should never consider young regions");
- return !hr->is_humongous() &&
+ return !hr->is_pinned() &&
hr->live_bytes() < _region_live_threshold_bytes;
}
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -30,6 +30,7 @@
#include "gc/g1/concurrentMarkThread.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
+#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1ErgoVerbose.hpp"
#include "gc/g1/g1Log.hpp"
#include "gc/g1/g1OopClosures.inline.hpp"
@@ -177,7 +178,7 @@
// will have them as guarantees at the beginning / end of the bitmap
// clearing to get some checking in the product.
assert(!_may_yield || _cm->cmThread()->during_cycle(), "invariant");
- assert(!_may_yield || !G1CollectedHeap::heap()->mark_in_progress(), "invariant");
+ assert(!_may_yield || !G1CollectedHeap::heap()->collector_state()->mark_in_progress(), "invariant");
}
return false;
@@ -518,7 +519,7 @@
_markStack(this),
// _finger set in set_non_marking_state
- _max_worker_id((uint)ParallelGCThreads),
+ _max_worker_id(ParallelGCThreads),
// _active_tasks set in set_non_marking_state
// _tasks set inside the constructor
_task_queues(new CMTaskQueueSet((int) _max_worker_id)),
@@ -579,8 +580,8 @@
_root_regions.init(_g1h, this);
if (ConcGCThreads > ParallelGCThreads) {
- warning("Can't have more ConcGCThreads (" UINTX_FORMAT ") "
- "than ParallelGCThreads (" UINTX_FORMAT ").",
+ warning("Can't have more ConcGCThreads (%u) "
+ "than ParallelGCThreads (%u).",
ConcGCThreads, ParallelGCThreads);
return;
}
@@ -604,20 +605,20 @@
double sleep_factor =
(1.0 - marking_task_overhead) / marking_task_overhead;
- FLAG_SET_ERGO(uintx, ConcGCThreads, (uint) marking_thread_num);
+ FLAG_SET_ERGO(uint, ConcGCThreads, (uint) marking_thread_num);
_sleep_factor = sleep_factor;
_marking_task_overhead = marking_task_overhead;
} else {
// Calculate the number of parallel marking threads by scaling
// the number of parallel GC threads.
- uint marking_thread_num = scale_parallel_threads((uint) ParallelGCThreads);
- FLAG_SET_ERGO(uintx, ConcGCThreads, marking_thread_num);
+ uint marking_thread_num = scale_parallel_threads(ParallelGCThreads);
+ FLAG_SET_ERGO(uint, ConcGCThreads, marking_thread_num);
_sleep_factor = 0.0;
_marking_task_overhead = 1.0;
}
assert(ConcGCThreads > 0, "Should have been set");
- _parallel_marking_threads = (uint) ConcGCThreads;
+ _parallel_marking_threads = ConcGCThreads;
_max_parallel_marking_threads = _parallel_marking_threads;
if (parallel_marking_threads() > 1) {
@@ -830,7 +831,7 @@
// marking bitmap and getting it ready for the next cycle. During
// this time no other cycle can start. So, let's make sure that this
// is the case.
- guarantee(!g1h->mark_in_progress(), "invariant");
+ guarantee(!g1h->collector_state()->mark_in_progress(), "invariant");
ClearBitmapHRClosure cl(this, _nextMarkBitMap, true /* may_yield */);
ParClearNextMarkBitmapTask task(&cl, parallel_marking_threads(), true);
@@ -844,7 +845,7 @@
// Repeat the asserts from above.
guarantee(cmThread()->during_cycle(), "invariant");
- guarantee(!g1h->mark_in_progress(), "invariant");
+ guarantee(!g1h->collector_state()->mark_in_progress(), "invariant");
}
class CheckBitmapClearHRClosure : public HeapRegionClosure {
@@ -1178,6 +1179,8 @@
};
void ConcurrentMark::scanRootRegions() {
+ double scan_start = os::elapsedTime();
+
// Start of concurrent marking.
ClassLoaderDataGraph::clear_claimed_marks();
@@ -1185,6 +1188,11 @@
// at least one root region to scan. So, if it's false, we
// should not attempt to do any further work.
if (root_regions()->scan_in_progress()) {
+ if (G1Log::fine()) {
+ gclog_or_tty->gclog_stamp(concurrent_gc_id());
+ gclog_or_tty->print_cr("[GC concurrent-root-region-scan-start]");
+ }
+
_parallel_marking_threads = calc_parallel_marking_threads();
assert(parallel_marking_threads() <= max_parallel_marking_threads(),
"Maximum number of marking threads exceeded");
@@ -1194,6 +1202,11 @@
_parallel_workers->set_active_workers(active_workers);
_parallel_workers->run_task(&task);
+ if (G1Log::fine()) {
+ gclog_or_tty->gclog_stamp(concurrent_gc_id());
+ gclog_or_tty->print_cr("[GC concurrent-root-region-scan-end, %1.7lf secs]", os::elapsedTime() - scan_start);
+ }
+
// It's possible that has_aborted() is true here without actually
// aborting the survivor scan earlier. This is OK as it's
// mainly used for sanity checking.
@@ -1254,7 +1267,7 @@
// If a full collection has happened, we shouldn't do this.
if (has_aborted()) {
- g1h->set_marking_complete(); // So bitmap clearing isn't confused
+ g1h->collector_state()->set_mark_in_progress(false); // So bitmap clearing isn't confused
return;
}
@@ -1783,7 +1796,7 @@
const HeapRegionSetCount& humongous_regions_removed() { return _humongous_regions_removed; }
bool doHeapRegion(HeapRegion *hr) {
- if (hr->is_continues_humongous()) {
+ if (hr->is_continues_humongous() || hr->is_archive()) {
return false;
}
// We use a claim value of zero here because all regions
@@ -1888,7 +1901,7 @@
// If a full collection has happened, we shouldn't do this.
if (has_aborted()) {
- g1h->set_marking_complete(); // So bitmap clearing isn't confused
+ g1h->collector_state()->set_mark_in_progress(false); // So bitmap clearing isn't confused
return;
}
@@ -1934,7 +1947,7 @@
}
size_t start_used_bytes = g1h->used();
- g1h->set_marking_complete();
+ g1h->collector_state()->set_mark_in_progress(false);
double count_end = os::elapsedTime();
double this_final_counting_time = (count_end - start);
@@ -2756,7 +2769,7 @@
void ConcurrentMark::verify_no_cset_oops() {
assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
- if (!G1CollectedHeap::heap()->mark_in_progress()) {
+ if (!G1CollectedHeap::heap()->collector_state()->mark_in_progress()) {
return;
}
@@ -2992,6 +3005,11 @@
// abandon current marking iteration due to a Full GC
void ConcurrentMark::abort() {
+ if (!cmThread()->during_cycle() || _has_aborted) {
+ // We haven't started a concurrent cycle or we have already aborted it. No need to do anything.
+ return;
+ }
+
// Clear all marks in the next bitmap for the next marking cycle. This will allow us to skip the next
// concurrent bitmap clearing.
_nextMarkBitMap->clearAll();
@@ -3009,12 +3027,8 @@
}
_first_overflow_barrier_sync.abort();
_second_overflow_barrier_sync.abort();
- const GCId& gc_id = _g1h->gc_tracer_cm()->gc_id();
- if (!gc_id.is_undefined()) {
- // We can do multiple full GCs before ConcurrentMarkThread::run() gets a chance
- // to detect that it was aborted. Only keep track of the first GC id that we aborted.
- _aborted_gc_id = gc_id;
- }
+ _aborted_gc_id = _g1h->gc_tracer_cm()->gc_id();
+ assert(!_aborted_gc_id.is_undefined(), "ConcurrentMark::abort() executed more than once?");
_has_aborted = true;
SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
--- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -78,7 +78,19 @@
}
};
-
+// We want to avoid that the logging from the concurrent thread is mixed
+// with the logging from a STW GC. So, if necessary join the STS to ensure
+// that the logging is done either before or after the STW logging.
+void ConcurrentMarkThread::cm_log(bool doit, bool join_sts, const char* fmt, ...) {
+ if (doit) {
+ SuspendibleThreadSetJoiner sts_joiner(join_sts);
+ va_list args;
+ va_start(args, fmt);
+ gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id());
+ gclog_or_tty->vprint_cr(fmt, args);
+ va_end(args);
+ }
+}
void ConcurrentMarkThread::run() {
initialize_in_thread();
@@ -110,28 +122,12 @@
// without the root regions have been scanned which would be a
// correctness issue.
- double scan_start = os::elapsedTime();
if (!cm()->has_aborted()) {
- if (G1Log::fine()) {
- gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id());
- gclog_or_tty->print_cr("[GC concurrent-root-region-scan-start]");
- }
-
_cm->scanRootRegions();
-
- double scan_end = os::elapsedTime();
- if (G1Log::fine()) {
- gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id());
- gclog_or_tty->print_cr("[GC concurrent-root-region-scan-end, %1.7lf secs]",
- scan_end - scan_start);
- }
}
double mark_start_sec = os::elapsedTime();
- if (G1Log::fine()) {
- gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id());
- gclog_or_tty->print_cr("[GC concurrent-mark-start]");
- }
+ cm_log(G1Log::fine(), true, "[GC concurrent-mark-start]");
int iter = 0;
do {
@@ -151,25 +147,15 @@
os::sleep(current_thread, sleep_time_ms, false);
}
- if (G1Log::fine()) {
- gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id());
- gclog_or_tty->print_cr("[GC concurrent-mark-end, %1.7lf secs]",
- mark_end_sec - mark_start_sec);
- }
+ cm_log(G1Log::fine(), true, "[GC concurrent-mark-end, %1.7lf secs]", mark_end_sec - mark_start_sec);
CMCheckpointRootsFinalClosure final_cl(_cm);
VM_CGC_Operation op(&final_cl, "GC remark", true /* needs_pll */);
VMThread::execute(&op);
}
if (cm()->restart_for_overflow()) {
- if (G1TraceMarkStackOverflow) {
- gclog_or_tty->print_cr("Restarting conc marking because of MS overflow "
- "in remark (restart #%d).", iter);
- }
- if (G1Log::fine()) {
- gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id());
- gclog_or_tty->print_cr("[GC concurrent-mark-restart-for-overflow]");
- }
+ cm_log(G1TraceMarkStackOverflow, true, "Restarting conc marking because of MS overflow in remark (restart #%d).", iter);
+ cm_log(G1Log::fine(), true, "[GC concurrent-mark-restart-for-overflow]");
}
} while (cm()->restart_for_overflow());
@@ -194,7 +180,7 @@
// We don't want to update the marking status if a GC pause
// is already underway.
SuspendibleThreadSetJoiner sts_join;
- g1h->set_marking_complete();
+ g1h->collector_state()->set_mark_in_progress(false);
}
// Check if cleanup set the free_regions_coming flag. If it
@@ -209,10 +195,7 @@
// reclaimed by cleanup.
double cleanup_start_sec = os::elapsedTime();
- if (G1Log::fine()) {
- gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id());
- gclog_or_tty->print_cr("[GC concurrent-cleanup-start]");
- }
+ cm_log(G1Log::fine(), true, "[GC concurrent-cleanup-start]");
// Now do the concurrent cleanup operation.
_cm->completeCleanup();
@@ -229,11 +212,7 @@
g1h->reset_free_regions_coming();
double cleanup_end_sec = os::elapsedTime();
- if (G1Log::fine()) {
- gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id());
- gclog_or_tty->print_cr("[GC concurrent-cleanup-end, %1.7lf secs]",
- cleanup_end_sec - cleanup_start_sec);
- }
+ cm_log(G1Log::fine(), true, "[GC concurrent-cleanup-end, %1.7lf secs]", cleanup_end_sec - cleanup_start_sec);
}
guarantee(cm()->cleanup_list_is_empty(),
"at this point there should be no regions on the cleanup list");
@@ -266,13 +245,8 @@
SuspendibleThreadSetJoiner sts_join;
if (!cm()->has_aborted()) {
g1_policy->record_concurrent_mark_cleanup_completed();
- }
- }
-
- if (cm()->has_aborted()) {
- if (G1Log::fine()) {
- gclog_or_tty->gclog_stamp(cm()->concurrent_gc_id());
- gclog_or_tty->print_cr("[GC concurrent-mark-abort]");
+ } else {
+ cm_log(G1Log::fine(), false, "[GC concurrent-mark-abort]");
}
}
--- a/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/concurrentMarkThread.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -40,6 +40,7 @@
double _vtime_accum; // Accumulated virtual time.
double _vtime_mark_accum;
+ void cm_log(bool doit, bool join_sts, const char* fmt, ...) ATTRIBUTE_PRINTF(4, 5);
public:
virtual void run();
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -26,6 +26,7 @@
#include "gc/g1/g1Allocator.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
+#include "gc/g1/g1MarkSweep.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionSet.inline.hpp"
@@ -44,6 +45,8 @@
HeapRegion** retained_old) {
HeapRegion* retained_region = *retained_old;
*retained_old = NULL;
+ assert(retained_region == NULL || !retained_region->is_archive(),
+ err_msg("Archive region should not be alloc region (index %u)", retained_region->hrm_index()));
// We will discard the current GC alloc region if:
// a) it's in the collection set (it can happen!),
@@ -65,7 +68,7 @@
// we allocate to in the region sets. We'll re-add it later, when
// it's retired again.
_g1h->_old_set.remove(retained_region);
- bool during_im = _g1h->g1_policy()->during_initial_mark_pause();
+ bool during_im = _g1h->collector_state()->during_initial_mark_pause();
retained_region->note_start_of_copying(during_im);
old->set(retained_region);
_g1h->_hr_printer.reuse(retained_region);
@@ -168,3 +171,153 @@
}
}
}
+
+G1ArchiveAllocator* G1ArchiveAllocator::create_allocator(G1CollectedHeap* g1h) {
+ // Create the archive allocator, and also enable archive object checking
+ // in mark-sweep, since we will be creating archive regions.
+ G1ArchiveAllocator* result = new G1ArchiveAllocator(g1h);
+ G1MarkSweep::enable_archive_object_check();
+ return result;
+}
+
+bool G1ArchiveAllocator::alloc_new_region() {
+ // Allocate the highest free region in the reserved heap,
+ // and add it to our list of allocated regions. It is marked
+ // archive and added to the old set.
+ HeapRegion* hr = _g1h->alloc_highest_free_region();
+ if (hr == NULL) {
+ return false;
+ }
+ assert(hr->is_empty(), err_msg("expected empty region (index %u)", hr->hrm_index()));
+ hr->set_archive();
+ _g1h->_old_set.add(hr);
+ _g1h->_hr_printer.alloc(hr, G1HRPrinter::Archive);
+ _allocated_regions.append(hr);
+ _allocation_region = hr;
+
+ // Set up _bottom and _max to begin allocating in the lowest
+ // min_region_size'd chunk of the allocated G1 region.
+ _bottom = hr->bottom();
+ _max = _bottom + HeapRegion::min_region_size_in_words();
+
+ // Tell mark-sweep that objects in this region are not to be marked.
+ G1MarkSweep::mark_range_archive(MemRegion(_bottom, HeapRegion::GrainWords));
+
+ // Since we've modified the old set, call update_sizes.
+ _g1h->g1mm()->update_sizes();
+ return true;
+}
+
+HeapWord* G1ArchiveAllocator::archive_mem_allocate(size_t word_size) {
+ assert(word_size != 0, "size must not be zero");
+ if (_allocation_region == NULL) {
+ if (!alloc_new_region()) {
+ return NULL;
+ }
+ }
+ HeapWord* old_top = _allocation_region->top();
+ assert(_bottom >= _allocation_region->bottom(),
+ err_msg("inconsistent allocation state: " PTR_FORMAT " < " PTR_FORMAT,
+ p2i(_bottom), p2i(_allocation_region->bottom())));
+ assert(_max <= _allocation_region->end(),
+ err_msg("inconsistent allocation state: " PTR_FORMAT " > " PTR_FORMAT,
+ p2i(_max), p2i(_allocation_region->end())));
+ assert(_bottom <= old_top && old_top <= _max,
+ err_msg("inconsistent allocation state: expected "
+ PTR_FORMAT " <= " PTR_FORMAT " <= " PTR_FORMAT,
+ p2i(_bottom), p2i(old_top), p2i(_max)));
+
+ // Allocate the next word_size words in the current allocation chunk.
+ // If allocation would cross the _max boundary, insert a filler and begin
+ // at the base of the next min_region_size'd chunk. Also advance to the next
+ // chunk if we don't yet cross the boundary, but the remainder would be too
+ // small to fill.
+ HeapWord* new_top = old_top + word_size;
+ size_t remainder = pointer_delta(_max, new_top);
+ if ((new_top > _max) ||
+ ((new_top < _max) && (remainder < CollectedHeap::min_fill_size()))) {
+ if (old_top != _max) {
+ size_t fill_size = pointer_delta(_max, old_top);
+ CollectedHeap::fill_with_object(old_top, fill_size);
+ _summary_bytes_used += fill_size * HeapWordSize;
+ }
+ _allocation_region->set_top(_max);
+ old_top = _bottom = _max;
+
+ // Check if we've just used up the last min_region_size'd chunk
+ // in the current region, and if so, allocate a new one.
+ if (_bottom != _allocation_region->end()) {
+ _max = _bottom + HeapRegion::min_region_size_in_words();
+ } else {
+ if (!alloc_new_region()) {
+ return NULL;
+ }
+ old_top = _allocation_region->bottom();
+ }
+ }
+ _allocation_region->set_top(old_top + word_size);
+ _summary_bytes_used += word_size * HeapWordSize;
+
+ return old_top;
+}
+
+void G1ArchiveAllocator::complete_archive(GrowableArray<MemRegion>* ranges,
+ size_t end_alignment_in_bytes) {
+ assert((end_alignment_in_bytes >> LogHeapWordSize) < HeapRegion::min_region_size_in_words(),
+ err_msg("alignment " SIZE_FORMAT " too large", end_alignment_in_bytes));
+ assert(is_size_aligned(end_alignment_in_bytes, HeapWordSize),
+ err_msg("alignment " SIZE_FORMAT " is not HeapWord (%u) aligned", end_alignment_in_bytes, HeapWordSize));
+
+ // If we've allocated nothing, simply return.
+ if (_allocation_region == NULL) {
+ return;
+ }
+
+ // If an end alignment was requested, insert filler objects.
+ if (end_alignment_in_bytes != 0) {
+ HeapWord* currtop = _allocation_region->top();
+ HeapWord* newtop = (HeapWord*)align_pointer_up(currtop, end_alignment_in_bytes);
+ size_t fill_size = pointer_delta(newtop, currtop);
+ if (fill_size != 0) {
+ if (fill_size < CollectedHeap::min_fill_size()) {
+ // If the required fill is smaller than we can represent,
+ // bump up to the next aligned address. We know we won't exceed the current
+ // region boundary because the max supported alignment is smaller than the min
+ // region size, and because the allocation code never leaves space smaller than
+ // the min_fill_size at the top of the current allocation region.
+ newtop = (HeapWord*)align_pointer_up(currtop + CollectedHeap::min_fill_size(),
+ end_alignment_in_bytes);
+ fill_size = pointer_delta(newtop, currtop);
+ }
+ HeapWord* fill = archive_mem_allocate(fill_size);
+ CollectedHeap::fill_with_objects(fill, fill_size);
+ }
+ }
+
+ // Loop through the allocated regions, and create MemRegions summarizing
+ // the allocated address range, combining contiguous ranges. Add the
+ // MemRegions to the GrowableArray provided by the caller.
+ int index = _allocated_regions.length() - 1;
+ assert(_allocated_regions.at(index) == _allocation_region,
+ err_msg("expected region %u at end of array, found %u",
+ _allocation_region->hrm_index(), _allocated_regions.at(index)->hrm_index()));
+ HeapWord* base_address = _allocation_region->bottom();
+ HeapWord* top = base_address;
+
+ while (index >= 0) {
+ HeapRegion* next = _allocated_regions.at(index);
+ HeapWord* new_base = next->bottom();
+ HeapWord* new_top = next->top();
+ if (new_base != top) {
+ ranges->append(MemRegion(base_address, pointer_delta(top, base_address)));
+ base_address = new_base;
+ }
+ top = new_top;
+ index = index - 1;
+ }
+
+ assert(top != base_address, err_msg("zero-sized range, address " PTR_FORMAT, p2i(base_address)));
+ ranges->append(MemRegion(base_address, pointer_delta(top, base_address)));
+ _allocated_regions.clear();
+ _allocation_region = NULL;
+};
--- a/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1Allocator.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -227,7 +227,7 @@
size_t word_sz,
AllocationContext_t context) {
G1PLAB* buffer = alloc_buffer(dest, context);
- if (_survivor_alignment_bytes == 0) {
+ if (_survivor_alignment_bytes == 0 || !dest.is_young()) {
return buffer->allocate(word_sz);
} else {
return buffer->allocate_aligned(word_sz, _survivor_alignment_bytes);
@@ -269,4 +269,72 @@
virtual void waste(size_t& wasted, size_t& undo_wasted);
};
+// G1ArchiveAllocator is used to allocate memory in archive
+// regions. Such regions are not modifiable by GC, being neither
+// scavenged nor compacted, or even marked in the object header.
+// They can contain no pointers to non-archive heap regions,
+class G1ArchiveAllocator : public CHeapObj<mtGC> {
+
+protected:
+ G1CollectedHeap* _g1h;
+
+ // The current allocation region
+ HeapRegion* _allocation_region;
+
+ // Regions allocated for the current archive range.
+ GrowableArray<HeapRegion*> _allocated_regions;
+
+ // The number of bytes used in the current range.
+ size_t _summary_bytes_used;
+
+ // Current allocation window within the current region.
+ HeapWord* _bottom;
+ HeapWord* _top;
+ HeapWord* _max;
+
+ // Allocate a new region for this archive allocator.
+ // Allocation is from the top of the reserved heap downward.
+ bool alloc_new_region();
+
+public:
+ G1ArchiveAllocator(G1CollectedHeap* g1h) :
+ _g1h(g1h),
+ _allocation_region(NULL),
+ _allocated_regions((ResourceObj::set_allocation_type((address) &_allocated_regions,
+ ResourceObj::C_HEAP),
+ 2), true /* C_Heap */),
+ _summary_bytes_used(0),
+ _bottom(NULL),
+ _top(NULL),
+ _max(NULL) { }
+
+ virtual ~G1ArchiveAllocator() {
+ assert(_allocation_region == NULL, "_allocation_region not NULL");
+ }
+
+ static G1ArchiveAllocator* create_allocator(G1CollectedHeap* g1h);
+
+ // Allocate memory for an individual object.
+ HeapWord* archive_mem_allocate(size_t word_size);
+
+ // Return the memory ranges used in the current archive, after
+ // aligning to the requested alignment.
+ void complete_archive(GrowableArray<MemRegion>* ranges,
+ size_t end_alignment_in_bytes);
+
+ // The number of bytes allocated by this allocator.
+ size_t used() {
+ return _summary_bytes_used;
+ }
+
+ // Clear the count of bytes allocated in prior G1 regions. This
+ // must be done when recalculate_use is used to reset the counter
+ // for the generic allocator, since it counts bytes in all G1
+ // regions, including those still associated with this allocator.
+ void clear_used() {
+ _summary_bytes_used = 0;
+ }
+
+};
+
#endif // SHARE_VM_GC_G1_G1ALLOCATOR_HPP
--- a/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1BiasedArray.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -26,6 +26,7 @@
#define SHARE_VM_GC_G1_G1BIASEDARRAY_HPP
#include "memory/allocation.hpp"
+#include "memory/memRegion.hpp"
#include "utilities/debug.hpp"
// Implements the common base functionality for arrays that contain provisions
@@ -128,6 +129,14 @@
return biased_base()[biased_index];
}
+ // Return the index of the element of the given array that covers the given
+ // word in the heap.
+ idx_t get_index_by_address(HeapWord* value) const {
+ idx_t biased_index = ((uintptr_t)value) >> this->shift_by();
+ this->verify_biased_index(biased_index);
+ return biased_index - _bias;
+ }
+
// Set the value of the array entry that corresponds to the given array.
void set_by_address(HeapWord * address, T value) {
idx_t biased_index = ((uintptr_t)address) >> this->shift_by();
@@ -135,6 +144,18 @@
biased_base()[biased_index] = value;
}
+ // Set the value of all array entries that correspond to addresses
+ // in the specified MemRegion.
+ void set_by_address(MemRegion range, T value) {
+ idx_t biased_start = ((uintptr_t)range.start()) >> this->shift_by();
+ idx_t biased_last = ((uintptr_t)range.last()) >> this->shift_by();
+ this->verify_biased_index(biased_start);
+ this->verify_biased_index(biased_last);
+ for (idx_t i = biased_start; i <= biased_last; i++) {
+ biased_base()[i] = value;
+ }
+ }
+
protected:
// Returns the address of the element the given address maps to
T* address_mapped_to(HeapWord* address) {
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -34,6 +34,7 @@
#include "gc/g1/g1AllocRegion.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
+#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1ErgoVerbose.hpp"
#include "gc/g1/g1EvacFailure.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
@@ -404,7 +405,7 @@
// can move in an incremental collection.
bool G1CollectedHeap::is_scavengable(const void* p) {
HeapRegion* hr = heap_region_containing(p);
- return !hr->is_humongous();
+ return !hr->is_pinned();
}
// Private methods.
@@ -907,6 +908,207 @@
return NULL;
}
+void G1CollectedHeap::begin_archive_alloc_range() {
+ assert_at_safepoint(true /* should_be_vm_thread */);
+ if (_archive_allocator == NULL) {
+ _archive_allocator = G1ArchiveAllocator::create_allocator(this);
+ }
+}
+
+bool G1CollectedHeap::is_archive_alloc_too_large(size_t word_size) {
+ // Allocations in archive regions cannot be of a size that would be considered
+ // humongous even for a minimum-sized region, because G1 region sizes/boundaries
+ // may be different at archive-restore time.
+ return word_size >= humongous_threshold_for(HeapRegion::min_region_size_in_words());
+}
+
+HeapWord* G1CollectedHeap::archive_mem_allocate(size_t word_size) {
+ assert_at_safepoint(true /* should_be_vm_thread */);
+ assert(_archive_allocator != NULL, "_archive_allocator not initialized");
+ if (is_archive_alloc_too_large(word_size)) {
+ return NULL;
+ }
+ return _archive_allocator->archive_mem_allocate(word_size);
+}
+
+void G1CollectedHeap::end_archive_alloc_range(GrowableArray<MemRegion>* ranges,
+ size_t end_alignment_in_bytes) {
+ assert_at_safepoint(true /* should_be_vm_thread */);
+ assert(_archive_allocator != NULL, "_archive_allocator not initialized");
+
+ // Call complete_archive to do the real work, filling in the MemRegion
+ // array with the archive regions.
+ _archive_allocator->complete_archive(ranges, end_alignment_in_bytes);
+ delete _archive_allocator;
+ _archive_allocator = NULL;
+}
+
+bool G1CollectedHeap::check_archive_addresses(MemRegion* ranges, size_t count) {
+ assert(ranges != NULL, "MemRegion array NULL");
+ assert(count != 0, "No MemRegions provided");
+ MemRegion reserved = _hrm.reserved();
+ for (size_t i = 0; i < count; i++) {
+ if (!reserved.contains(ranges[i].start()) || !reserved.contains(ranges[i].last())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) {
+ assert(ranges != NULL, "MemRegion array NULL");
+ assert(count != 0, "No MemRegions provided");
+ MutexLockerEx x(Heap_lock);
+
+ MemRegion reserved = _hrm.reserved();
+ HeapWord* prev_last_addr = NULL;
+ HeapRegion* prev_last_region = NULL;
+
+ // Temporarily disable pretouching of heap pages. This interface is used
+ // when mmap'ing archived heap data in, so pre-touching is wasted.
+ FlagSetting fs(AlwaysPreTouch, false);
+
+ // Enable archive object checking in G1MarkSweep. We have to let it know
+ // about each archive range, so that objects in those ranges aren't marked.
+ G1MarkSweep::enable_archive_object_check();
+
+ // For each specified MemRegion range, allocate the corresponding G1
+ // regions and mark them as archive regions. We expect the ranges in
+ // ascending starting address order, without overlap.
+ for (size_t i = 0; i < count; i++) {
+ MemRegion curr_range = ranges[i];
+ HeapWord* start_address = curr_range.start();
+ size_t word_size = curr_range.word_size();
+ HeapWord* last_address = curr_range.last();
+ size_t commits = 0;
+
+ guarantee(reserved.contains(start_address) && reserved.contains(last_address),
+ err_msg("MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]",
+ p2i(start_address), p2i(last_address)));
+ guarantee(start_address > prev_last_addr,
+ err_msg("Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT ,
+ p2i(start_address), p2i(prev_last_addr)));
+ prev_last_addr = last_address;
+
+ // Check for ranges that start in the same G1 region in which the previous
+ // range ended, and adjust the start address so we don't try to allocate
+ // the same region again. If the current range is entirely within that
+ // region, skip it, just adjusting the recorded top.
+ HeapRegion* start_region = _hrm.addr_to_region(start_address);
+ if ((prev_last_region != NULL) && (start_region == prev_last_region)) {
+ start_address = start_region->end();
+ if (start_address > last_address) {
+ _allocator->increase_used(word_size * HeapWordSize);
+ start_region->set_top(last_address + 1);
+ continue;
+ }
+ start_region->set_top(start_address);
+ curr_range = MemRegion(start_address, last_address + 1);
+ start_region = _hrm.addr_to_region(start_address);
+ }
+
+ // Perform the actual region allocation, exiting if it fails.
+ // Then note how much new space we have allocated.
+ if (!_hrm.allocate_containing_regions(curr_range, &commits)) {
+ return false;
+ }
+ _allocator->increase_used(word_size * HeapWordSize);
+ if (commits != 0) {
+ ergo_verbose1(ErgoHeapSizing,
+ "attempt heap expansion",
+ ergo_format_reason("allocate archive regions")
+ ergo_format_byte("total size"),
+ HeapRegion::GrainWords * HeapWordSize * commits);
+ }
+
+ // Mark each G1 region touched by the range as archive, add it to the old set,
+ // and set the allocation context and top.
+ HeapRegion* curr_region = _hrm.addr_to_region(start_address);
+ HeapRegion* last_region = _hrm.addr_to_region(last_address);
+ prev_last_region = last_region;
+
+ while (curr_region != NULL) {
+ assert(curr_region->is_empty() && !curr_region->is_pinned(),
+ err_msg("Region already in use (index %u)", curr_region->hrm_index()));
+ _hr_printer.alloc(curr_region, G1HRPrinter::Archive);
+ curr_region->set_allocation_context(AllocationContext::system());
+ curr_region->set_archive();
+ _old_set.add(curr_region);
+ if (curr_region != last_region) {
+ curr_region->set_top(curr_region->end());
+ curr_region = _hrm.next_region_in_heap(curr_region);
+ } else {
+ curr_region->set_top(last_address + 1);
+ curr_region = NULL;
+ }
+ }
+
+ // Notify mark-sweep of the archive range.
+ G1MarkSweep::mark_range_archive(curr_range);
+ }
+ return true;
+}
+
+void G1CollectedHeap::fill_archive_regions(MemRegion* ranges, size_t count) {
+ assert(ranges != NULL, "MemRegion array NULL");
+ assert(count != 0, "No MemRegions provided");
+ MemRegion reserved = _hrm.reserved();
+ HeapWord *prev_last_addr = NULL;
+ HeapRegion* prev_last_region = NULL;
+
+ // For each MemRegion, create filler objects, if needed, in the G1 regions
+ // that contain the address range. The address range actually within the
+ // MemRegion will not be modified. That is assumed to have been initialized
+ // elsewhere, probably via an mmap of archived heap data.
+ MutexLockerEx x(Heap_lock);
+ for (size_t i = 0; i < count; i++) {
+ HeapWord* start_address = ranges[i].start();
+ HeapWord* last_address = ranges[i].last();
+
+ assert(reserved.contains(start_address) && reserved.contains(last_address),
+ err_msg("MemRegion outside of heap [" PTR_FORMAT ", " PTR_FORMAT "]",
+ p2i(start_address), p2i(last_address)));
+ assert(start_address > prev_last_addr,
+ err_msg("Ranges not in ascending order: " PTR_FORMAT " <= " PTR_FORMAT ,
+ p2i(start_address), p2i(prev_last_addr)));
+
+ HeapRegion* start_region = _hrm.addr_to_region(start_address);
+ HeapRegion* last_region = _hrm.addr_to_region(last_address);
+ HeapWord* bottom_address = start_region->bottom();
+
+ // Check for a range beginning in the same region in which the
+ // previous one ended.
+ if (start_region == prev_last_region) {
+ bottom_address = prev_last_addr + 1;
+ }
+
+ // Verify that the regions were all marked as archive regions by
+ // alloc_archive_regions.
+ HeapRegion* curr_region = start_region;
+ while (curr_region != NULL) {
+ guarantee(curr_region->is_archive(),
+ err_msg("Expected archive region at index %u", curr_region->hrm_index()));
+ if (curr_region != last_region) {
+ curr_region = _hrm.next_region_in_heap(curr_region);
+ } else {
+ curr_region = NULL;
+ }
+ }
+
+ prev_last_addr = last_address;
+ prev_last_region = last_region;
+
+ // Fill the memory below the allocated range with dummy object(s),
+ // if the region bottom does not match the range start, or if the previous
+ // range ended within the same G1 region, and there is a gap.
+ if (start_address != bottom_address) {
+ size_t fill_size = pointer_delta(start_address, bottom_address);
+ G1CollectedHeap::fill_with_objects(bottom_address, fill_size);
+ _allocator->increase_used(fill_size * HeapWordSize);
+ }
+ }
+}
+
HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size,
uint* gc_count_before_ret,
uint* gclocker_retry_count_ret) {
@@ -1039,7 +1241,7 @@
} else {
HeapWord* result = humongous_obj_allocate(word_size, context);
if (result != NULL && g1_policy()->need_to_start_conc_mark("STW humongous allocation")) {
- g1_policy()->set_initiate_conc_mark_if_possible();
+ collector_state()->set_initiate_conc_mark_if_possible(true);
}
return result;
}
@@ -1131,6 +1333,8 @@
}
} else if (hr->is_continues_humongous()) {
_hr_printer->post_compaction(hr, G1HRPrinter::ContinuesHumongous);
+ } else if (hr->is_archive()) {
+ _hr_printer->post_compaction(hr, G1HRPrinter::Archive);
} else if (hr->is_old()) {
_hr_printer->post_compaction(hr, G1HRPrinter::Old);
} else {
@@ -1250,7 +1454,7 @@
g1_policy()->stop_incremental_cset_building();
tear_down_region_sets(false /* free_list_only */);
- g1_policy()->set_gcs_are_young(true);
+ collector_state()->set_gcs_are_young(true);
// See the comments in g1CollectedHeap.hpp and
// G1CollectedHeap::ref_processing_init() about
@@ -1714,16 +1918,15 @@
_ref_processor_stw(NULL),
_bot_shared(NULL),
_evac_failure_scan_stack(NULL),
- _mark_in_progress(false),
_cg1r(NULL),
_g1mm(NULL),
_refine_cte_cl(NULL),
- _full_collection(false),
_secondary_free_list("Secondary Free List", new SecondaryFreeRegionListMtSafeChecker()),
_old_set("Old Set", false /* humongous */, new OldRegionSetMtSafeChecker()),
_humongous_set("Master Humongous Set", true /* humongous */, new HumongousRegionSetMtSafeChecker()),
_humongous_reclaim_candidates(),
_has_humongous_reclaim_candidates(false),
+ _archive_allocator(NULL),
_free_regions_coming(false),
_young_list(new YoungList(this)),
_gc_time_stamp(0),
@@ -1733,7 +1936,6 @@
_surviving_young_words(NULL),
_old_marking_cycles_started(0),
_old_marking_cycles_completed(0),
- _concurrent_cycle_started(false),
_heap_summary_sent(false),
_in_cset_fast_test(),
_dirty_cards_region_list(NULL),
@@ -1750,9 +1952,13 @@
_workers->initialize_workers();
_allocator = G1Allocator::create_allocator(this);
- _humongous_object_threshold_in_words = HeapRegion::GrainWords / 2;
-
- int n_queues = (int)ParallelGCThreads;
+ _humongous_object_threshold_in_words = humongous_threshold_for(HeapRegion::GrainWords);
+
+ // Override the default _filler_array_max_size so that no humongous filler
+ // objects are created.
+ _filler_array_max_size = _humongous_object_threshold_in_words;
+
+ uint n_queues = ParallelGCThreads;
_task_queues = new RefToScanQueueSet(n_queues);
uint n_rem_sets = HeapRegionRemSet::num_par_rem_sets();
@@ -1762,7 +1968,7 @@
_worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(uint, n_queues, mtGC);
_evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC);
- for (int i = 0; i < n_queues; i++) {
+ for (uint i = 0; i < n_queues; i++) {
RefToScanQueue* q = new RefToScanQueue();
q->initialize();
_task_queues->register_queue(i, q);
@@ -2064,11 +2270,11 @@
new ReferenceProcessor(mr, // span
ParallelRefProcEnabled && (ParallelGCThreads > 1),
// mt processing
- (uint) ParallelGCThreads,
+ ParallelGCThreads,
// degree of mt processing
(ParallelGCThreads > 1) || (ConcGCThreads > 1),
// mt discovery
- (uint) MAX2(ParallelGCThreads, ConcGCThreads),
+ MAX2(ParallelGCThreads, ConcGCThreads),
// degree of mt discovery
false,
// Reference discovery is not atomic
@@ -2081,11 +2287,11 @@
new ReferenceProcessor(mr, // span
ParallelRefProcEnabled && (ParallelGCThreads > 1),
// mt processing
- (uint) ParallelGCThreads,
+ ParallelGCThreads,
// degree of mt processing
(ParallelGCThreads > 1),
// mt discovery
- (uint) ParallelGCThreads,
+ ParallelGCThreads,
// degree of mt discovery
true,
// Reference discovery is atomic
@@ -2165,7 +2371,11 @@
// Computes the sum of the storage used by the various regions.
size_t G1CollectedHeap::used() const {
- return _allocator->used();
+ size_t result = _allocator->used();
+ if (_archive_allocator != NULL) {
+ result += _archive_allocator->used();
+ }
+ return result;
}
size_t G1CollectedHeap::used_unlocked() const {
@@ -2288,7 +2498,7 @@
}
void G1CollectedHeap::register_concurrent_cycle_start(const Ticks& start_time) {
- _concurrent_cycle_started = true;
+ collector_state()->set_concurrent_cycle_started(true);
_gc_timer_cm->register_gc_start(start_time);
_gc_tracer_cm->report_gc_start(gc_cause(), _gc_timer_cm->gc_start());
@@ -2296,7 +2506,7 @@
}
void G1CollectedHeap::register_concurrent_cycle_end() {
- if (_concurrent_cycle_started) {
+ if (collector_state()->concurrent_cycle_started()) {
if (_cm->has_aborted()) {
_gc_tracer_cm->report_concurrent_mode_failure();
}
@@ -2305,13 +2515,13 @@
_gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions());
// Clear state variables to prepare for the next concurrent cycle.
- _concurrent_cycle_started = false;
+ collector_state()->set_concurrent_cycle_started(false);
_heap_summary_sent = false;
}
}
void G1CollectedHeap::trace_heap_after_concurrent_cycle() {
- if (_concurrent_cycle_started) {
+ if (collector_state()->concurrent_cycle_started()) {
// This function can be called when:
// the cleanup pause is run
// the concurrent cycle is aborted before the cleanup pause.
@@ -2325,22 +2535,6 @@
}
}
-G1YCType G1CollectedHeap::yc_type() {
- bool is_young = g1_policy()->gcs_are_young();
- bool is_initial_mark = g1_policy()->during_initial_mark_pause();
- bool is_during_mark = mark_in_progress();
-
- if (is_initial_mark) {
- return InitialMark;
- } else if (is_during_mark) {
- return DuringMark;
- } else if (is_young) {
- return Normal;
- } else {
- return Mixed;
- }
-}
-
void G1CollectedHeap::collect(GCCause::Cause cause) {
assert_heap_not_locked();
@@ -2594,7 +2788,7 @@
HeapRegion* G1CollectedHeap::next_compaction_region(const HeapRegion* from) const {
HeapRegion* result = _hrm.next_region_in_heap(from);
- while (result != NULL && result->is_humongous()) {
+ while (result != NULL && result->is_pinned()) {
result = _hrm.next_region_in_heap(result);
}
return result;
@@ -2902,6 +3096,31 @@
size_t live_bytes() { return _live_bytes; }
};
+class VerifyArchiveOopClosure: public OopClosure {
+public:
+ VerifyArchiveOopClosure(HeapRegion *hr) { }
+ void do_oop(narrowOop *p) { do_oop_work(p); }
+ void do_oop( oop *p) { do_oop_work(p); }
+
+ template <class T> void do_oop_work(T *p) {
+ oop obj = oopDesc::load_decode_heap_oop(p);
+ guarantee(obj == NULL || G1MarkSweep::in_archive_range(obj),
+ err_msg("Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT,
+ p2i(p), p2i(obj)));
+ }
+};
+
+class VerifyArchiveRegionClosure: public ObjectClosure {
+public:
+ VerifyArchiveRegionClosure(HeapRegion *hr) { }
+ // Verify that all object pointers are to archive regions.
+ void do_object(oop o) {
+ VerifyArchiveOopClosure checkOop(NULL);
+ assert(o != NULL, "Should not be here for NULL oops");
+ o->oop_iterate_no_header(&checkOop);
+ }
+};
+
class VerifyRegionClosure: public HeapRegionClosure {
private:
bool _par;
@@ -2921,6 +3140,13 @@
}
bool doHeapRegion(HeapRegion* r) {
+ // For archive regions, verify there are no heap pointers to
+ // non-pinned regions. For all others, verify liveness info.
+ if (r->is_archive()) {
+ VerifyArchiveRegionClosure verify_oop_pointers(r);
+ r->object_iterate(&verify_oop_pointers);
+ return true;
+ }
if (!r->is_continues_humongous()) {
bool failures = false;
r->verify(_vo, &failures);
@@ -3105,7 +3331,7 @@
switch (vo) {
case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj, hr);
case VerifyOption_G1UseNextMarking: return is_obj_ill(obj, hr);
- case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked();
+ case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked() && !hr->is_archive();
default: ShouldNotReachHere();
}
return false; // keep some compilers happy
@@ -3116,7 +3342,10 @@
switch (vo) {
case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj);
case VerifyOption_G1UseNextMarking: return is_obj_ill(obj);
- case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked();
+ case VerifyOption_G1UseMarkWord: {
+ HeapRegion* hr = _hrm.addr_to_region((HeapWord*)obj);
+ return !obj->is_gc_marked() && !hr->is_archive();
+ }
default: ShouldNotReachHere();
}
return false; // keep some compilers happy
@@ -3149,7 +3378,7 @@
st->cr();
st->print_cr("Heap Regions: (Y=young(eden), SU=young(survivor), "
"HS=humongous(starts), HC=humongous(continues), "
- "CS=collection set, F=free, TS=gc time stamp, "
+ "CS=collection set, F=free, A=archive, TS=gc time stamp, "
"PTAMS=previous top-at-mark-start, "
"NTAMS=next top-at-mark-start)");
PrintRegionClosure blk(st);
@@ -3251,6 +3480,28 @@
}
#endif // PRODUCT
+G1HeapSummary G1CollectedHeap::create_g1_heap_summary() {
+ YoungList* young_list = heap()->young_list();
+
+ size_t eden_used_bytes = young_list->eden_used_bytes();
+ size_t survivor_used_bytes = young_list->survivor_used_bytes();
+
+ size_t eden_capacity_bytes =
+ (g1_policy()->young_list_target_length() * HeapRegion::GrainBytes) - survivor_used_bytes;
+
+ VirtualSpaceSummary heap_summary = create_heap_space_summary();
+ return G1HeapSummary(heap_summary, used(), eden_used_bytes, eden_capacity_bytes, survivor_used_bytes);
+}
+
+void G1CollectedHeap::trace_heap(GCWhen::Type when, const GCTracer* gc_tracer) {
+ const G1HeapSummary& heap_summary = create_g1_heap_summary();
+ gc_tracer->report_gc_heap_summary(when, heap_summary);
+
+ const MetaspaceSummary& metaspace_summary = create_metaspace_summary();
+ gc_tracer->report_metaspace_summary(when, metaspace_summary);
+}
+
+
G1CollectedHeap* G1CollectedHeap::heap() {
CollectedHeap* heap = Universe::heap();
assert(heap != NULL, "Uninitialized access to G1CollectedHeap::heap()");
@@ -3587,8 +3838,8 @@
gclog_or_tty->gclog_stamp(_gc_tracer_stw->gc_id());
GCCauseString gc_cause_str = GCCauseString("GC pause", gc_cause())
- .append(g1_policy()->gcs_are_young() ? "(young)" : "(mixed)")
- .append(g1_policy()->during_initial_mark_pause() ? " (initial-mark)" : "");
+ .append(collector_state()->gcs_are_young() ? "(young)" : "(mixed)")
+ .append(collector_state()->during_initial_mark_pause() ? " (initial-mark)" : "");
gclog_or_tty->print("[%s", (const char*)gc_cause_str);
}
@@ -3616,6 +3867,21 @@
gclog_or_tty->flush();
}
+void G1CollectedHeap::wait_for_root_region_scanning() {
+ double scan_wait_start = os::elapsedTime();
+ // We have to wait until the CM threads finish scanning the
+ // root regions as it's the only way to ensure that all the
+ // objects on them have been correctly scanned before we start
+ // moving them during the GC.
+ bool waited = _cm->root_regions()->wait_until_scan_finished();
+ double wait_time_ms = 0.0;
+ if (waited) {
+ double scan_wait_end = os::elapsedTime();
+ wait_time_ms = (scan_wait_end - scan_wait_start) * 1000.0;
+ }
+ g1_policy()->phase_times()->record_root_region_scan_wait_time(wait_time_ms);
+}
+
bool
G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
assert_at_safepoint(true /* should_be_vm_thread */);
@@ -3632,6 +3898,8 @@
SvcGCMarker sgcm(SvcGCMarker::MINOR);
ResourceMark rm;
+ wait_for_root_region_scanning();
+
G1Log::update_level();
print_heap_before_gc();
trace_heap_before_gc(_gc_tracer_stw);
@@ -3645,29 +3913,29 @@
g1_policy()->decide_on_conc_mark_initiation();
// We do not allow initial-mark to be piggy-backed on a mixed GC.
- assert(!g1_policy()->during_initial_mark_pause() ||
- g1_policy()->gcs_are_young(), "sanity");
+ assert(!collector_state()->during_initial_mark_pause() ||
+ collector_state()->gcs_are_young(), "sanity");
// We also do not allow mixed GCs during marking.
- assert(!mark_in_progress() || g1_policy()->gcs_are_young(), "sanity");
+ assert(!collector_state()->mark_in_progress() || collector_state()->gcs_are_young(), "sanity");
// Record whether this pause is an initial mark. When the current
// thread has completed its logging output and it's safe to signal
// the CM thread, the flag's value in the policy has been reset.
- bool should_start_conc_mark = g1_policy()->during_initial_mark_pause();
+ bool should_start_conc_mark = collector_state()->during_initial_mark_pause();
// Inner scope for scope based logging, timers, and stats collection
{
EvacuationInfo evacuation_info;
- if (g1_policy()->during_initial_mark_pause()) {
+ if (collector_state()->during_initial_mark_pause()) {
// We are about to start a marking cycle, so we increment the
// full collection counter.
increment_old_marking_cycles_started();
register_concurrent_cycle_start(_gc_timer_stw->gc_start());
}
- _gc_tracer_stw->report_yc_type(yc_type());
+ _gc_tracer_stw->report_yc_type(collector_state()->yc_type());
TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty);
@@ -3677,7 +3945,7 @@
workers()->set_active_workers(active_workers);
double pause_start_sec = os::elapsedTime();
- g1_policy()->phase_times()->note_gc_start(active_workers, mark_in_progress());
+ g1_policy()->phase_times()->note_gc_start(active_workers, collector_state()->mark_in_progress());
log_gc_header();
TraceCollectorStats tcs(g1mm()->incremental_collection_counters());
@@ -3753,25 +4021,12 @@
g1_policy()->record_collection_pause_start(sample_start_time_sec);
- double scan_wait_start = os::elapsedTime();
- // We have to wait until the CM threads finish scanning the
- // root regions as it's the only way to ensure that all the
- // objects on them have been correctly scanned before we start
- // moving them during the GC.
- bool waited = _cm->root_regions()->wait_until_scan_finished();
- double wait_time_ms = 0.0;
- if (waited) {
- double scan_wait_end = os::elapsedTime();
- wait_time_ms = (scan_wait_end - scan_wait_start) * 1000.0;
- }
- g1_policy()->phase_times()->record_root_region_scan_wait_time(wait_time_ms);
-
#if YOUNG_LIST_VERBOSE
gclog_or_tty->print_cr("\nAfter recording pause start.\nYoung_list:");
_young_list->print();
#endif // YOUNG_LIST_VERBOSE
- if (g1_policy()->during_initial_mark_pause()) {
+ if (collector_state()->during_initial_mark_pause()) {
concurrent_mark()->checkpointRootsInitialPre();
}
@@ -3848,6 +4103,9 @@
if (evacuation_failed()) {
_allocator->set_used(recalculate_used());
+ if (_archive_allocator != NULL) {
+ _archive_allocator->clear_used();
+ }
for (uint i = 0; i < ParallelGCThreads; i++) {
if (_evacuation_failed_info_array[i].has_failed()) {
_gc_tracer_stw->report_evacuation_failed(_evacuation_failed_info_array[i]);
@@ -3859,12 +4117,12 @@
_allocator->increase_used(g1_policy()->bytes_copied_during_gc());
}
- if (g1_policy()->during_initial_mark_pause()) {
+ if (collector_state()->during_initial_mark_pause()) {
// We have to do this before we notify the CM threads that
// they can start working to make sure that all the
// appropriate initialization is done on the CM object.
concurrent_mark()->checkpointRootsInitialPost();
- set_marking_started();
+ collector_state()->set_mark_in_progress(true);
// Note that we don't actually trigger the CM thread at
// this point. We do that later when we're sure that
// the current thread has completed its logging output.
@@ -4343,7 +4601,7 @@
pss.set_evac_failure_closure(&evac_failure_cl);
- bool only_young = _g1h->g1_policy()->gcs_are_young();
+ bool only_young = _g1h->collector_state()->gcs_are_young();
// Non-IM young GC.
G1ParCopyClosure<G1BarrierNone, G1MarkNone> scan_only_root_cl(_g1h, &pss, rp);
@@ -4369,7 +4627,7 @@
bool trace_metadata = false;
- if (_g1h->g1_policy()->during_initial_mark_pause()) {
+ if (_g1h->collector_state()->during_initial_mark_pause()) {
// We also need to mark copied objects.
strong_root_cl = &scan_mark_root_cl;
strong_cld_cl = &scan_mark_cld_cl;
@@ -5021,7 +5279,7 @@
OopClosure* copy_non_heap_cl = &only_copy_non_heap_cl;
- if (_g1h->g1_policy()->during_initial_mark_pause()) {
+ if (_g1h->collector_state()->during_initial_mark_pause()) {
// We also need to mark copied objects.
copy_non_heap_cl = ©_mark_non_heap_cl;
}
@@ -5122,7 +5380,7 @@
OopClosure* copy_non_heap_cl = &only_copy_non_heap_cl;
- if (_g1h->g1_policy()->during_initial_mark_pause()) {
+ if (_g1h->collector_state()->during_initial_mark_pause()) {
// We also need to mark copied objects.
copy_non_heap_cl = ©_mark_non_heap_cl;
}
@@ -5234,7 +5492,7 @@
OopClosure* copy_non_heap_cl = &only_copy_non_heap_cl;
- if (g1_policy()->during_initial_mark_pause()) {
+ if (collector_state()->during_initial_mark_pause()) {
// We also need to mark copied objects.
copy_non_heap_cl = ©_mark_non_heap_cl;
}
@@ -5342,7 +5600,7 @@
G1RootProcessor root_processor(this, n_workers);
G1ParTask g1_par_task(this, _task_queues, &root_processor, n_workers);
// InitialMark needs claim bits to keep track of the marked-through CLDs.
- if (g1_policy()->during_initial_mark_pause()) {
+ if (collector_state()->during_initial_mark_pause()) {
ClassLoaderDataGraph::clear_claimed_marks();
}
@@ -5598,7 +5856,7 @@
// We reset mark_in_progress() before we reset _cmThread->in_progress() and in this window
// we do the clearing of the next bitmap concurrently. Thus, we can not verify the bitmap
// if we happen to be in that state.
- if (mark_in_progress() || !_cmThread->in_progress()) {
+ if (collector_state()->mark_in_progress() || !_cmThread->in_progress()) {
res_n = verify_no_bits_over_tams("next", next_bitmap, ntams, end);
}
if (!res_p || !res_n) {
@@ -6169,13 +6427,18 @@
assert(!r->is_young(), "we should not come across young regions");
if (r->is_humongous()) {
- // We ignore humongous regions, we left the humongous set unchanged
+ // We ignore humongous regions. We left the humongous set unchanged.
} else {
// Objects that were compacted would have ended up on regions
- // that were previously old or free.
+ // that were previously old or free. Archive regions (which are
+ // old) will not have been touched.
assert(r->is_free() || r->is_old(), "invariant");
- // We now consider them old, so register as such.
- r->set_old();
+ // We now consider them old, so register as such. Leave
+ // archive regions set that way, however, while still adding
+ // them to the old set.
+ if (!r->is_archive()) {
+ r->set_old();
+ }
_old_set->add(r);
}
_total_used += r->used();
@@ -6201,6 +6464,9 @@
if (!free_list_only) {
_allocator->set_used(cl.total_used());
+ if (_archive_allocator != NULL) {
+ _archive_allocator->clear_used();
+ }
}
assert(_allocator->used_unlocked() == recalculate_used(),
err_msg("inconsistent _allocator->used_unlocked(), "
@@ -6279,7 +6545,7 @@
_hr_printer.alloc(new_alloc_region, G1HRPrinter::Old);
check_bitmaps("Old Region Allocation", new_alloc_region);
}
- bool during_im = g1_policy()->during_initial_mark_pause();
+ bool during_im = collector_state()->during_initial_mark_pause();
new_alloc_region->note_start_of_copying(during_im);
return new_alloc_region;
}
@@ -6290,7 +6556,7 @@
void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region,
size_t allocated_bytes,
InCSetState dest) {
- bool during_im = g1_policy()->during_initial_mark_pause();
+ bool during_im = collector_state()->during_initial_mark_pause();
alloc_region->note_end_of_copying(during_im);
g1_policy()->record_bytes_copied_during_gc(allocated_bytes);
if (dest.is_young()) {
@@ -6301,6 +6567,25 @@
_hr_printer.retire(alloc_region);
}
+HeapRegion* G1CollectedHeap::alloc_highest_free_region() {
+ bool expanded = false;
+ uint index = _hrm.find_highest_free(&expanded);
+
+ if (index != G1_NO_HRM_INDEX) {
+ if (expanded) {
+ ergo_verbose1(ErgoHeapSizing,
+ "attempt heap expansion",
+ ergo_format_reason("requested address range outside heap bounds")
+ ergo_format_byte("region size"),
+ HeapRegion::GrainWords * HeapWordSize);
+ }
+ _hrm.allocate_free_regions_starting_at(index, 1);
+ return region_at(index);
+ }
+ return NULL;
+}
+
+
// Heap region set verification
class VerifyRegionListsClosure : public HeapRegionClosure {
@@ -6337,6 +6622,9 @@
assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrm_index()));
_old_count.increment(1u, hr->capacity());
} else {
+ // There are no other valid region types. Check for one invalid
+ // one we can identify: pinned without old or humongous set.
+ assert(!hr->is_pinned(), err_msg("Heap region %u is pinned but not old (archive) or humongous.", hr->hrm_index()));
ShouldNotReachHere();
}
return false;
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -31,6 +31,7 @@
#include "gc/g1/g1AllocationContext.hpp"
#include "gc/g1/g1Allocator.hpp"
#include "gc/g1/g1BiasedArray.hpp"
+#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1HRPrinter.hpp"
#include "gc/g1/g1InCSetState.hpp"
#include "gc/g1/g1MonitoringSupport.hpp"
@@ -187,6 +188,7 @@
friend class SurvivorGCAllocRegion;
friend class OldGCAllocRegion;
friend class G1Allocator;
+ friend class G1ArchiveAllocator;
// Closures used in implementation.
friend class G1ParScanThreadState;
@@ -249,6 +251,9 @@
// Class that handles the different kinds of allocations.
G1Allocator* _allocator;
+ // Class that handles archive allocation ranges.
+ G1ArchiveAllocator* _archive_allocator;
+
// Statistics for each allocation context
AllocationContextStats _allocation_context_stats;
@@ -328,6 +333,9 @@
// (d) cause == _g1_humongous_allocation
bool should_do_concurrent_full_gc(GCCause::Cause cause);
+ // indicates whether we are in young or mixed GC mode
+ G1CollectorState _collector_state;
+
// Keeps track of how many "old marking cycles" (i.e., Full GCs or
// concurrent cycles) we have started.
volatile uint _old_marking_cycles_started;
@@ -336,7 +344,6 @@
// concurrent cycles) we have completed.
volatile uint _old_marking_cycles_completed;
- bool _concurrent_cycle_started;
bool _heap_summary_sent;
// This is a non-product method that is helpful for testing. It is
@@ -367,6 +374,8 @@
void log_gc_header();
void log_gc_footer(double pause_time_sec);
+ void trace_heap(GCWhen::Type when, const GCTracer* tracer);
+
// These are macros so that, if the assert fires, we get the correct
// line number, file, etc.
@@ -571,6 +580,10 @@
void retire_gc_alloc_region(HeapRegion* alloc_region,
size_t allocated_bytes, InCSetState dest);
+ // Allocate the highest free region in the reserved heap. This will commit
+ // regions as necessary.
+ HeapRegion* alloc_highest_free_region();
+
// - if explicit_gc is true, the GC is for a System.gc() or a heap
// inspection request and should collect the entire heap
// - if clear_all_soft_refs is true, all soft references should be
@@ -701,8 +714,6 @@
void register_concurrent_cycle_end();
void trace_heap_after_concurrent_cycle();
- G1YCType yc_type();
-
G1HRPrinter* hr_printer() { return &_hr_printer; }
// Frees a non-humongous region by initializing its contents and
@@ -728,6 +739,44 @@
void free_humongous_region(HeapRegion* hr,
FreeRegionList* free_list,
bool par);
+
+ // Facility for allocating in 'archive' regions in high heap memory and
+ // recording the allocated ranges. These should all be called from the
+ // VM thread at safepoints, without the heap lock held. They can be used
+ // to create and archive a set of heap regions which can be mapped at the
+ // same fixed addresses in a subsequent JVM invocation.
+ void begin_archive_alloc_range();
+
+ // Check if the requested size would be too large for an archive allocation.
+ bool is_archive_alloc_too_large(size_t word_size);
+
+ // Allocate memory of the requested size from the archive region. This will
+ // return NULL if the size is too large or if no memory is available. It
+ // does not trigger a garbage collection.
+ HeapWord* archive_mem_allocate(size_t word_size);
+
+ // Optionally aligns the end address and returns the allocated ranges in
+ // an array of MemRegions in order of ascending addresses.
+ void end_archive_alloc_range(GrowableArray<MemRegion>* ranges,
+ size_t end_alignment_in_bytes = 0);
+
+ // Facility for allocating a fixed range within the heap and marking
+ // the containing regions as 'archive'. For use at JVM init time, when the
+ // caller may mmap archived heap data at the specified range(s).
+ // Verify that the MemRegions specified in the argument array are within the
+ // reserved heap.
+ bool check_archive_addresses(MemRegion* range, size_t count);
+
+ // Commit the appropriate G1 regions containing the specified MemRegions
+ // and mark them as 'archive' regions. The regions in the array must be
+ // non-overlapping and in order of ascending address.
+ bool alloc_archive_regions(MemRegion* range, size_t count);
+
+ // Insert any required filler objects in the G1 regions around the specified
+ // ranges to make the regions parseable. This must be called after
+ // alloc_archive_regions, and after class loading has occurred.
+ void fill_archive_regions(MemRegion* range, size_t count);
+
protected:
// Shrink the garbage-first heap by at most the given size (in bytes!).
@@ -756,6 +805,8 @@
bool* succeeded,
GCCause::Cause gc_cause);
+ void wait_for_root_region_scanning();
+
// The guts of the incremental collection pause, executed by the vm
// thread. It returns false if it is unable to do the collection due
// to the GC locker being active, true otherwise
@@ -791,7 +842,6 @@
// The concurrent marker (and the thread it runs in.)
ConcurrentMark* _cm;
ConcurrentMarkThread* _cmThread;
- bool _mark_in_progress;
// The concurrent refiner.
ConcurrentG1Refine* _cg1r;
@@ -1019,6 +1069,8 @@
return CollectedHeap::G1CollectedHeap;
}
+ G1CollectorState* collector_state() { return &_collector_state; }
+
// The current policy object for the collector.
G1CollectorPolicy* g1_policy() const { return _g1_policy; }
@@ -1391,6 +1443,11 @@
return word_size > _humongous_object_threshold_in_words;
}
+ // Returns the humongous threshold for a specific region size
+ static size_t humongous_threshold_for(size_t region_size) {
+ return (region_size / 2);
+ }
+
// Update mod union table with the set of dirty cards.
void updateModUnion();
@@ -1399,17 +1456,6 @@
// bits.
void markModUnionRange(MemRegion mr);
- // Records the fact that a marking phase is no longer in progress.
- void set_marking_complete() {
- _mark_in_progress = false;
- }
- void set_marking_started() {
- _mark_in_progress = true;
- }
- bool mark_in_progress() {
- return _mark_in_progress;
- }
-
// Print the maximum heap capacity.
virtual size_t max_capacity() const;
@@ -1448,21 +1494,23 @@
// Determine if an object is dead, given the object and also
// the region to which the object belongs. An object is dead
- // iff a) it was not allocated since the last mark and b) it
- // is not marked.
+ // iff a) it was not allocated since the last mark, b) it
+ // is not marked, and c) it is not in an archive region.
bool is_obj_dead(const oop obj, const HeapRegion* hr) const {
return
!hr->obj_allocated_since_prev_marking(obj) &&
- !isMarkedPrev(obj);
+ !isMarkedPrev(obj) &&
+ !hr->is_archive();
}
// This function returns true when an object has been
// around since the previous marking and hasn't yet
- // been marked during this marking.
+ // been marked during this marking, and is not in an archive region.
bool is_obj_ill(const oop obj, const HeapRegion* hr) const {
return
!hr->obj_allocated_since_next_marking(obj) &&
- !isMarkedNext(obj);
+ !isMarkedNext(obj) &&
+ !hr->is_archive();
}
// Determine if an object is dead, given only the object itself.
@@ -1522,14 +1570,6 @@
void redirty_logged_cards();
// Verification
- // The following is just to alert the verification code
- // that a full collection has occurred and that the
- // remembered sets are no longer up to date.
- bool _full_collection;
- void set_full_collection() { _full_collection = true;}
- void clear_full_collection() {_full_collection = false;}
- bool full_collection() {return _full_collection;}
-
// Perform any cleanup actions necessary before allowing a verification.
virtual void prepare_for_verify();
@@ -1565,6 +1605,8 @@
bool is_obj_dead_cond(const oop obj,
const VerifyOption vo) const;
+ G1HeapSummary create_g1_heap_summary();
+
// Printing
virtual void print_on(outputStream* st) const;
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.inline.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -29,6 +29,7 @@
#include "gc/g1/g1AllocRegion.inline.hpp"
#include "gc/g1/g1CollectedHeap.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
+#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1SATBCardTableModRefBS.hpp"
#include "gc/g1/heapRegionManager.inline.hpp"
#include "gc/g1/heapRegionSet.inline.hpp"
@@ -288,9 +289,9 @@
_evacuation_failure_alot_for_current_gc = (elapsed_gcs >= G1EvacuationFailureALotInterval);
// Now check if G1EvacuationFailureALot is enabled for the current GC type.
- const bool gcs_are_young = g1_policy()->gcs_are_young();
- const bool during_im = g1_policy()->during_initial_mark_pause();
- const bool during_marking = mark_in_progress();
+ const bool gcs_are_young = collector_state()->gcs_are_young();
+ const bool during_im = collector_state()->during_initial_mark_pause();
+ const bool during_marking = collector_state()->mark_in_progress();
_evacuation_failure_alot_for_current_gc &=
evacuation_failure_alot_for_gc_type(gcs_are_young,
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -107,22 +107,11 @@
_pause_time_target_ms((double) MaxGCPauseMillis),
- _gcs_are_young(true),
-
- _during_marking(false),
- _in_marking_window(false),
- _in_marking_window_im(false),
-
_recent_prev_end_times_for_all_gcs_sec(
new TruncatedSeq(NumPrevPausesForHeuristics)),
_recent_avg_pause_time_ratio(0.0),
- _initiate_conc_mark_if_possible(false),
- _during_initial_mark_pause(false),
- _last_young_gc(false),
- _last_gc_was_young(false),
-
_eden_used_bytes_before_gc(0),
_survivor_used_bytes_before_gc(0),
_heap_used_bytes_before_gc(0),
@@ -334,6 +323,8 @@
}
}
+G1CollectorState* G1CollectorPolicy::collector_state() { return _g1->collector_state(); }
+
G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true),
_min_desired_young_length(0), _max_desired_young_length(0) {
if (FLAG_IS_CMDLINE(NewRatio)) {
@@ -552,7 +543,7 @@
uint young_list_target_length = 0;
if (adaptive_young_list_length()) {
- if (gcs_are_young()) {
+ if (collector_state()->gcs_are_young()) {
young_list_target_length =
calculate_young_list_target_length(rs_lengths,
base_min_length,
@@ -594,7 +585,7 @@
uint desired_min_length,
uint desired_max_length) {
assert(adaptive_young_list_length(), "pre-condition");
- assert(gcs_are_young(), "only call this for young GCs");
+ assert(collector_state()->gcs_are_young(), "only call this for young GCs");
// In case some edge-condition makes the desired max length too small...
if (desired_max_length <= desired_min_length) {
@@ -697,7 +688,7 @@
for (HeapRegion * r = _recorded_survivor_head;
r != NULL && r != _recorded_survivor_tail->get_next_young_region();
r = r->get_next_young_region()) {
- survivor_regions_evac_time += predict_region_elapsed_time_ms(r, gcs_are_young());
+ survivor_regions_evac_time += predict_region_elapsed_time_ms(r, collector_state()->gcs_are_young());
}
return survivor_regions_evac_time;
}
@@ -782,7 +773,7 @@
_full_collection_start_sec = os::elapsedTime();
record_heap_size_info_at_start(true /* full */);
// Release the future to-space so that it is available for compaction into.
- _g1->set_full_collection();
+ collector_state()->set_full_collection(true);
}
void G1CollectorPolicy::record_full_collection_end() {
@@ -796,16 +787,16 @@
update_recent_gc_times(end_sec, full_gc_time_ms);
- _g1->clear_full_collection();
+ collector_state()->set_full_collection(false);
// "Nuke" the heuristics that control the young/mixed GC
// transitions and make sure we start with young GCs after the Full GC.
- set_gcs_are_young(true);
- _last_young_gc = false;
- clear_initiate_conc_mark_if_possible();
- clear_during_initial_mark_pause();
- _in_marking_window = false;
- _in_marking_window_im = false;
+ collector_state()->set_gcs_are_young(true);
+ collector_state()->set_last_young_gc(false);
+ collector_state()->set_initiate_conc_mark_if_possible(false);
+ collector_state()->set_during_initial_mark_pause(false);
+ collector_state()->set_in_marking_window(false);
+ collector_state()->set_in_marking_window_im(false);
_short_lived_surv_rate_group->start_adding_regions();
// also call this on any additional surv rate groups
@@ -845,7 +836,7 @@
_collection_set_bytes_used_before = 0;
_bytes_copied_during_gc = 0;
- _last_gc_was_young = false;
+ collector_state()->set_last_gc_was_young(false);
// do that for any other surv rate groups
_short_lived_surv_rate_group->stop_adding_regions();
@@ -856,15 +847,15 @@
void G1CollectorPolicy::record_concurrent_mark_init_end(double
mark_init_elapsed_time_ms) {
- _during_marking = true;
- assert(!initiate_conc_mark_if_possible(), "we should have cleared it by now");
- clear_during_initial_mark_pause();
+ collector_state()->set_during_marking(true);
+ assert(!collector_state()->initiate_conc_mark_if_possible(), "we should have cleared it by now");
+ collector_state()->set_during_initial_mark_pause(false);
_cur_mark_stop_world_time_ms = mark_init_elapsed_time_ms;
}
void G1CollectorPolicy::record_concurrent_mark_remark_start() {
_mark_remark_start_sec = os::elapsedTime();
- _during_marking = false;
+ collector_state()->set_during_marking(false);
}
void G1CollectorPolicy::record_concurrent_mark_remark_end() {
@@ -882,8 +873,8 @@
}
void G1CollectorPolicy::record_concurrent_mark_cleanup_completed() {
- _last_young_gc = true;
- _in_marking_window = false;
+ collector_state()->set_last_young_gc(true);
+ collector_state()->set_in_marking_window(false);
}
void G1CollectorPolicy::record_concurrent_pause() {
@@ -904,7 +895,7 @@
size_t alloc_byte_size = alloc_word_size * HeapWordSize;
if ((cur_used_bytes + alloc_byte_size) > marking_initiating_used_threshold) {
- if (gcs_are_young() && !_last_young_gc) {
+ if (collector_state()->gcs_are_young() && !collector_state()->last_young_gc()) {
ergo_verbose5(ErgoConcCycles,
"request concurrent cycle initiation",
ergo_format_reason("occupancy higher than threshold")
@@ -959,14 +950,14 @@
}
#endif // PRODUCT
- last_pause_included_initial_mark = during_initial_mark_pause();
+ last_pause_included_initial_mark = collector_state()->during_initial_mark_pause();
if (last_pause_included_initial_mark) {
record_concurrent_mark_init_end(0.0);
} else if (need_to_start_conc_mark("end of GC")) {
// Note: this might have already been set, if during the last
// pause we decided to start a cycle but at the beginning of
// this pause we decided to postpone it. That's OK.
- set_initiate_conc_mark_if_possible();
+ collector_state()->set_initiate_conc_mark_if_possible(true);
}
_mmu_tracker->add_pause(end_time_sec - pause_time_ms/1000.0,
@@ -1028,37 +1019,37 @@
}
}
- bool new_in_marking_window = _in_marking_window;
+ bool new_in_marking_window = collector_state()->in_marking_window();
bool new_in_marking_window_im = false;
if (last_pause_included_initial_mark) {
new_in_marking_window = true;
new_in_marking_window_im = true;
}
- if (_last_young_gc) {
+ if (collector_state()->last_young_gc()) {
// This is supposed to to be the "last young GC" before we start
// doing mixed GCs. Here we decide whether to start mixed GCs or not.
if (!last_pause_included_initial_mark) {
if (next_gc_should_be_mixed("start mixed GCs",
"do not start mixed GCs")) {
- set_gcs_are_young(false);
+ collector_state()->set_gcs_are_young(false);
}
} else {
ergo_verbose0(ErgoMixedGCs,
"do not start mixed GCs",
ergo_format_reason("concurrent cycle is about to start"));
}
- _last_young_gc = false;
+ collector_state()->set_last_young_gc(false);
}
- if (!_last_gc_was_young) {
+ if (!collector_state()->last_gc_was_young()) {
// This is a mixed GC. Here we decide whether to continue doing
// mixed GCs or not.
if (!next_gc_should_be_mixed("continue mixed GCs",
"do not continue mixed GCs")) {
- set_gcs_are_young(true);
+ collector_state()->set_gcs_are_young(true);
}
}
@@ -1077,7 +1068,7 @@
double cost_per_entry_ms = 0.0;
if (cards_scanned > 10) {
cost_per_entry_ms = phase_times()->average_time_ms(G1GCPhaseTimes::ScanRS) / (double) cards_scanned;
- if (_last_gc_was_young) {
+ if (collector_state()->last_gc_was_young()) {
_cost_per_entry_ms_seq->add(cost_per_entry_ms);
} else {
_mixed_cost_per_entry_ms_seq->add(cost_per_entry_ms);
@@ -1087,7 +1078,7 @@
if (_max_rs_lengths > 0) {
double cards_per_entry_ratio =
(double) cards_scanned / (double) _max_rs_lengths;
- if (_last_gc_was_young) {
+ if (collector_state()->last_gc_was_young()) {
_young_cards_per_entry_ratio_seq->add(cards_per_entry_ratio);
} else {
_mixed_cards_per_entry_ratio_seq->add(cards_per_entry_ratio);
@@ -1119,7 +1110,7 @@
if (copied_bytes > 0) {
cost_per_byte_ms = phase_times()->average_time_ms(G1GCPhaseTimes::ObjCopy) / (double) copied_bytes;
- if (_in_marking_window) {
+ if (collector_state()->in_marking_window()) {
_cost_per_byte_ms_during_cm_seq->add(cost_per_byte_ms);
} else {
_cost_per_byte_ms_seq->add(cost_per_byte_ms);
@@ -1162,8 +1153,8 @@
_rs_lengths_seq->add((double) _max_rs_lengths);
}
- _in_marking_window = new_in_marking_window;
- _in_marking_window_im = new_in_marking_window_im;
+ collector_state()->set_in_marking_window(new_in_marking_window);
+ collector_state()->set_in_marking_window_im(new_in_marking_window_im);
_free_regions_at_end_of_collection = _g1->num_free_regions();
update_young_list_target_length();
@@ -1301,7 +1292,7 @@
G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) {
size_t rs_length = predict_rs_length_diff();
size_t card_num;
- if (gcs_are_young()) {
+ if (collector_state()->gcs_are_young()) {
card_num = predict_young_card_num(rs_length);
} else {
card_num = predict_non_young_card_num(rs_length);
@@ -1467,7 +1458,7 @@
ergo_format_reason("requested by GC cause")
ergo_format_str("GC cause"),
GCCause::to_string(gc_cause));
- set_initiate_conc_mark_if_possible();
+ collector_state()->set_initiate_conc_mark_if_possible(true);
return true;
} else {
ergo_verbose1(ErgoConcCycles,
@@ -1484,13 +1475,13 @@
// We are about to decide on whether this pause will be an
// initial-mark pause.
- // First, during_initial_mark_pause() should not be already set. We
+ // First, collector_state()->during_initial_mark_pause() should not be already set. We
// will set it here if we have to. However, it should be cleared by
// the end of the pause (it's only set for the duration of an
// initial-mark pause).
- assert(!during_initial_mark_pause(), "pre-condition");
+ assert(!collector_state()->during_initial_mark_pause(), "pre-condition");
- if (initiate_conc_mark_if_possible()) {
+ if (collector_state()->initiate_conc_mark_if_possible()) {
// We had noticed on a previous pause that the heap occupancy has
// gone over the initiating threshold and we should start a
// concurrent marking cycle. So we might initiate one.
@@ -1501,10 +1492,10 @@
// it has completed the last one. So we can go ahead and
// initiate a new cycle.
- set_during_initial_mark_pause();
+ collector_state()->set_during_initial_mark_pause(true);
// We do not allow mixed GCs during marking.
- if (!gcs_are_young()) {
- set_gcs_are_young(true);
+ if (!collector_state()->gcs_are_young()) {
+ collector_state()->set_gcs_are_young(true);
ergo_verbose0(ErgoMixedGCs,
"end mixed GCs",
ergo_format_reason("concurrent cycle is about to start"));
@@ -1512,7 +1503,7 @@
// And we can now clear initiate_conc_mark_if_possible() as
// we've already acted on it.
- clear_initiate_conc_mark_if_possible();
+ collector_state()->set_initiate_conc_mark_if_possible(false);
ergo_verbose0(ErgoConcCycles,
"initiate concurrent cycle",
@@ -1686,7 +1677,7 @@
// retiring the current allocation region) or a concurrent
// refine thread (RSet sampling).
- double region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, gcs_are_young());
+ double region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young());
size_t used_bytes = hr->used();
_inc_cset_recorded_rs_lengths += rs_length;
_inc_cset_predicted_elapsed_time_ms += region_elapsed_time_ms;
@@ -1721,7 +1712,7 @@
_inc_cset_recorded_rs_lengths_diffs += rs_lengths_diff;
double old_elapsed_time_ms = hr->predicted_elapsed_time_ms();
- double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, gcs_are_young());
+ double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young());
double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms;
_inc_cset_predicted_elapsed_time_ms_diffs += elapsed_ms_diff;
@@ -1914,9 +1905,9 @@
ergo_format_ms("target pause time"),
_pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms);
- _last_gc_was_young = gcs_are_young() ? true : false;
+ collector_state()->set_last_gc_was_young(collector_state()->gcs_are_young());
- if (_last_gc_was_young) {
+ if (collector_state()->last_gc_was_young()) {
_trace_young_gen_time_data.increment_young_collection_count();
} else {
_trace_young_gen_time_data.increment_mixed_collection_count();
@@ -1967,7 +1958,7 @@
// Set the start of the non-young choice time.
double non_young_start_time_sec = young_end_time_sec;
- if (!gcs_are_young()) {
+ if (!collector_state()->gcs_are_young()) {
CollectionSetChooser* cset_chooser = _collectionSetChooser;
cset_chooser->verify();
const uint min_old_cset_length = calc_min_old_cset_length();
@@ -2013,7 +2004,7 @@
break;
}
- double predicted_time_ms = predict_region_elapsed_time_ms(hr, gcs_are_young());
+ double predicted_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young());
if (check_time_remaining) {
if (predicted_time_ms > time_remaining_ms) {
// Too expensive for the current CSet.
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -27,6 +27,7 @@
#include "gc/g1/collectionSetChooser.hpp"
#include "gc/g1/g1Allocator.hpp"
+#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1MMUTracker.hpp"
#include "gc/shared/collectorPolicy.hpp"
@@ -193,9 +194,6 @@
double _stop_world_start;
- // indicates whether we are in young or mixed GC mode
- bool _gcs_are_young;
-
uint _young_list_target_length;
uint _young_list_fixed_length;
@@ -203,12 +201,6 @@
// locker is active. This should be >= _young_list_target_length;
uint _young_list_max_length;
- bool _last_gc_was_young;
-
- bool _during_marking;
- bool _in_marking_window;
- bool _in_marking_window_im;
-
SurvRateGroup* _short_lived_surv_rate_group;
SurvRateGroup* _survivor_surv_rate_group;
// add here any more surv rate groups
@@ -218,10 +210,6 @@
double _reserve_factor;
uint _reserve_regions;
- bool during_marking() {
- return _during_marking;
- }
-
enum PredictionConstants {
TruncatedSeqLength = 10
};
@@ -363,7 +351,7 @@
}
double predict_rs_scan_time_ms(size_t card_num) {
- if (gcs_are_young()) {
+ if (collector_state()->gcs_are_young()) {
return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq);
} else {
return predict_mixed_rs_scan_time_ms(card_num);
@@ -390,7 +378,7 @@
}
double predict_object_copy_time_ms(size_t bytes_to_copy) {
- if (_in_marking_window && !_in_marking_window_im) {
+ if (collector_state()->during_concurrent_mark()) {
return predict_object_copy_time_ms_during_cm(bytes_to_copy);
} else {
return (double) bytes_to_copy *
@@ -428,7 +416,7 @@
double predict_survivor_regions_evac_time();
void cset_regions_freed() {
- bool propagate = _last_gc_was_young && !_in_marking_window;
+ bool propagate = collector_state()->should_propagate();
_short_lived_surv_rate_group->all_surviving_words_recorded(propagate);
_survivor_surv_rate_group->all_surviving_words_recorded(propagate);
// also call it on any more surv rate groups
@@ -552,33 +540,6 @@
return _recent_avg_pause_time_ratio;
}
- // At the end of a pause we check the heap occupancy and we decide
- // whether we will start a marking cycle during the next pause. If
- // we decide that we want to do that, we will set this parameter to
- // true. So, this parameter will stay true between the end of a
- // pause and the beginning of a subsequent pause (not necessarily
- // the next one, see the comments on the next field) when we decide
- // that we will indeed start a marking cycle and do the initial-mark
- // work.
- volatile bool _initiate_conc_mark_if_possible;
-
- // If initiate_conc_mark_if_possible() is set at the beginning of a
- // pause, it is a suggestion that the pause should start a marking
- // cycle by doing the initial-mark work. However, it is possible
- // that the concurrent marking thread is still finishing up the
- // previous marking cycle (e.g., clearing the next marking
- // bitmap). If that is the case we cannot start a new cycle and
- // we'll have to wait for the concurrent marking thread to finish
- // what it is doing. In this case we will postpone the marking cycle
- // initiation decision for the next pause. When we eventually decide
- // to start a cycle, we will set _during_initial_mark_pause which
- // will stay true until the end of the initial-mark pause and it's
- // the condition that indicates that a pause is doing the
- // initial-mark work.
- volatile bool _during_initial_mark_pause;
-
- bool _last_young_gc;
-
// This set of variables tracks the collector efficiency, in order to
// determine whether we should initiate a new marking.
double _cur_mark_stop_world_time_ms;
@@ -647,6 +608,8 @@
return CollectorPolicy::G1CollectorPolicyKind;
}
+ G1CollectorState* collector_state();
+
G1GCPhaseTimes* phase_times() const { return _phase_times; }
// Check the current value of the young list RSet lengths and
@@ -786,14 +749,6 @@
void print_collection_set(HeapRegion* list_head, outputStream* st);
#endif // !PRODUCT
- bool initiate_conc_mark_if_possible() { return _initiate_conc_mark_if_possible; }
- void set_initiate_conc_mark_if_possible() { _initiate_conc_mark_if_possible = true; }
- void clear_initiate_conc_mark_if_possible() { _initiate_conc_mark_if_possible = false; }
-
- bool during_initial_mark_pause() { return _during_initial_mark_pause; }
- void set_during_initial_mark_pause() { _during_initial_mark_pause = true; }
- void clear_during_initial_mark_pause(){ _during_initial_mark_pause = false; }
-
// This sets the initiate_conc_mark_if_possible() flag to start a
// new cycle, as long as we are not already in one. It's best if it
// is called during a safepoint when the test whether a cycle is in
@@ -837,13 +792,6 @@
return _young_list_max_length;
}
- bool gcs_are_young() {
- return _gcs_are_young;
- }
- void set_gcs_are_young(bool gcs_are_young) {
- _gcs_are_young = gcs_are_young;
- }
-
bool adaptive_young_list_length() {
return _young_gen_sizer->adaptive_young_list_length();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorState.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_GC_G1_G1COLLECTORSTATE_HPP
+#define SHARE_VM_GC_G1_G1COLLECTORSTATE_HPP
+
+#include "utilities/globalDefinitions.hpp"
+#include "gc/g1/g1YCTypes.hpp"
+
+// Various state variables that indicate
+// the phase of the G1 collection.
+class G1CollectorState VALUE_OBJ_CLASS_SPEC {
+ // Indicates whether we are in "full young" or "mixed" GC mode.
+ bool _gcs_are_young;
+ // Was the last GC "young"?
+ bool _last_gc_was_young;
+ // Is this the "last young GC" before we start doing mixed GCs?
+ // Set after a concurrent mark has completed.
+ bool _last_young_gc;
+
+ // If initiate_conc_mark_if_possible() is set at the beginning of a
+ // pause, it is a suggestion that the pause should start a marking
+ // cycle by doing the initial-mark work. However, it is possible
+ // that the concurrent marking thread is still finishing up the
+ // previous marking cycle (e.g., clearing the next marking
+ // bitmap). If that is the case we cannot start a new cycle and
+ // we'll have to wait for the concurrent marking thread to finish
+ // what it is doing. In this case we will postpone the marking cycle
+ // initiation decision for the next pause. When we eventually decide
+ // to start a cycle, we will set _during_initial_mark_pause which
+ // will stay true until the end of the initial-mark pause and it's
+ // the condition that indicates that a pause is doing the
+ // initial-mark work.
+ volatile bool _during_initial_mark_pause;
+
+ // At the end of a pause we check the heap occupancy and we decide
+ // whether we will start a marking cycle during the next pause. If
+ // we decide that we want to do that, we will set this parameter to
+ // true. So, this parameter will stay true between the end of a
+ // pause and the beginning of a subsequent pause (not necessarily
+ // the next one, see the comments on the next field) when we decide
+ // that we will indeed start a marking cycle and do the initial-mark
+ // work.
+ volatile bool _initiate_conc_mark_if_possible;
+
+ // NOTE: if some of these are synonyms for others,
+ // the redundant fields should be eliminated. XXX
+ bool _during_marking;
+ bool _mark_in_progress;
+ bool _in_marking_window;
+ bool _in_marking_window_im;
+
+ bool _concurrent_cycle_started;
+ bool _full_collection;
+
+ public:
+ G1CollectorState() :
+ _gcs_are_young(true),
+ _last_gc_was_young(false),
+ _last_young_gc(false),
+
+ _during_initial_mark_pause(false),
+ _initiate_conc_mark_if_possible(false),
+
+ _during_marking(false),
+ _mark_in_progress(false),
+ _in_marking_window(false),
+ _in_marking_window_im(false),
+ _concurrent_cycle_started(false),
+ _full_collection(false) {}
+
+ // Setters
+ void set_gcs_are_young(bool v) { _gcs_are_young = v; }
+ void set_last_gc_was_young(bool v) { _last_gc_was_young = v; }
+ void set_last_young_gc(bool v) { _last_young_gc = v; }
+ void set_during_initial_mark_pause(bool v) { _during_initial_mark_pause = v; }
+ void set_initiate_conc_mark_if_possible(bool v) { _initiate_conc_mark_if_possible = v; }
+ void set_during_marking(bool v) { _during_marking = v; }
+ void set_mark_in_progress(bool v) { _mark_in_progress = v; }
+ void set_in_marking_window(bool v) { _in_marking_window = v; }
+ void set_in_marking_window_im(bool v) { _in_marking_window_im = v; }
+ void set_concurrent_cycle_started(bool v) { _concurrent_cycle_started = v; }
+ void set_full_collection(bool v) { _full_collection = v; }
+
+ // Getters
+ bool gcs_are_young() { return _gcs_are_young; }
+ bool last_gc_was_young() { return _last_gc_was_young; }
+ bool last_young_gc() { return _last_young_gc; }
+ bool during_initial_mark_pause() { return _during_initial_mark_pause; }
+ bool initiate_conc_mark_if_possible() { return _initiate_conc_mark_if_possible; }
+ bool during_marking() { return _during_marking; }
+ bool mark_in_progress() { return _mark_in_progress; }
+ bool in_marking_window() { return _in_marking_window; }
+ bool in_marking_window_im() { return _in_marking_window_im; }
+ bool concurrent_cycle_started() { return _concurrent_cycle_started; }
+ bool full_collection() { return _full_collection; }
+
+ // Composite booleans (clients worry about flickering)
+ bool during_concurrent_mark() {
+ return (_in_marking_window && !_in_marking_window_im);
+ }
+
+ bool should_propagate() { // XXX should have a more suitable state name or abstraction for this
+ return (_last_young_gc && !_in_marking_window);
+ }
+
+ G1YCType yc_type() {
+ if (during_initial_mark_pause()) {
+ return InitialMark;
+ } else if (mark_in_progress()) {
+ return DuringMark;
+ } else if (gcs_are_young()) {
+ return Normal;
+ } else {
+ return Mixed;
+ }
+ }
+};
+
+#endif /* SHARE_VM_GC_G1_G1COLLECTORSTATE_HPP */
--- a/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1EvacFailure.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -26,6 +26,7 @@
#include "gc/g1/concurrentMark.inline.hpp"
#include "gc/g1/dirtyCardQueue.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
+#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1EvacFailure.hpp"
#include "gc/g1/g1OopClosures.inline.hpp"
#include "gc/g1/g1_globals.hpp"
@@ -186,10 +187,10 @@
}
bool doHeapRegion(HeapRegion *hr) {
- bool during_initial_mark = _g1h->g1_policy()->during_initial_mark_pause();
- bool during_conc_mark = _g1h->mark_in_progress();
+ bool during_initial_mark = _g1h->collector_state()->during_initial_mark_pause();
+ bool during_conc_mark = _g1h->collector_state()->mark_in_progress();
- assert(!hr->is_humongous(), "sanity");
+ assert(!hr->is_pinned(), err_msg("Unexpected pinned region at index %u", hr->hrm_index()));
assert(hr->in_collection_set(), "bad CS");
if (_hrclaimer->claim_region(hr->hrm_index())) {
--- a/hotspot/src/share/vm/gc/g1/g1HRPrinter.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HRPrinter.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -54,6 +54,7 @@
case SingleHumongous: return "SingleH";
case StartsHumongous: return "StartsH";
case ContinuesHumongous: return "ContinuesH";
+ case Archive: return "Archive";
default: ShouldNotReachHere();
}
// trying to keep the Windows compiler happy
--- a/hotspot/src/share/vm/gc/g1/g1HRPrinter.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1HRPrinter.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -52,7 +52,8 @@
Old,
SingleHumongous,
StartsHumongous,
- ContinuesHumongous
+ ContinuesHumongous,
+ Archive
} RegionType;
typedef enum {
--- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -57,6 +57,9 @@
class HeapRegion;
+bool G1MarkSweep::_archive_check_enabled = false;
+G1ArchiveRegionMap G1MarkSweep::_archive_region_map;
+
void G1MarkSweep::invoke_at_safepoint(ReferenceProcessor* rp,
bool clear_all_softrefs) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
@@ -212,7 +215,7 @@
// point all the oops to the new location
MarkSweep::adjust_pointers(obj);
}
- } else {
+ } else if (!r->is_pinned()) {
// This really ought to be "as_CompactibleSpace"...
r->adjust_pointers();
}
@@ -275,7 +278,7 @@
}
hr->reset_during_compaction();
}
- } else {
+ } else if (!hr->is_pinned()) {
hr->compact();
}
return false;
@@ -298,6 +301,26 @@
}
+void G1MarkSweep::enable_archive_object_check() {
+ assert(!_archive_check_enabled, "archive range check already enabled");
+ _archive_check_enabled = true;
+ size_t length = Universe::heap()->max_capacity();
+ _archive_region_map.initialize((HeapWord*)Universe::heap()->base(),
+ (HeapWord*)Universe::heap()->base() + length,
+ HeapRegion::GrainBytes);
+}
+
+void G1MarkSweep::mark_range_archive(MemRegion range) {
+ assert(_archive_check_enabled, "archive range check not enabled");
+ _archive_region_map.set_by_address(range, true);
+}
+
+bool G1MarkSweep::in_archive_range(oop object) {
+ // This is the out-of-line part of is_archive_object test, done separately
+ // to avoid additional performance impact when the check is not enabled.
+ return _archive_region_map.get_by_address((HeapWord*)object);
+}
+
void G1MarkSweep::prepare_compaction_work(G1PrepareCompactClosure* blk) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
g1h->heap_region_iterate(blk);
@@ -357,7 +380,7 @@
} else {
assert(hr->is_continues_humongous(), "Invalid humongous.");
}
- } else {
+ } else if (!hr->is_pinned()) {
prepare_for_compaction(hr, hr->end());
}
return false;
--- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -44,6 +44,7 @@
//
// Class unloading will only occur when a full gc is invoked.
class G1PrepareCompactClosure;
+class G1ArchiveRegionMap;
class G1MarkSweep : AllStatic {
public:
@@ -54,7 +55,22 @@
static STWGCTimer* gc_timer() { return GenMarkSweep::_gc_timer; }
static SerialOldTracer* gc_tracer() { return GenMarkSweep::_gc_tracer; }
+ // Create the _archive_region_map which is used to identify archive objects.
+ static void enable_archive_object_check();
+
+ // Mark the regions containing the specified address range as archive regions.
+ static void mark_range_archive(MemRegion range);
+
+ // Check if an object is in an archive region using the _archive_region_map.
+ static bool in_archive_range(oop object);
+
+ // Check if archive object checking is enabled, to avoid calling in_archive_range
+ // unnecessarily.
+ static bool archive_check_enabled() { return G1MarkSweep::_archive_check_enabled; }
+
private:
+ static bool _archive_check_enabled;
+ static G1ArchiveRegionMap _archive_region_map;
// Mark live objects
static void mark_sweep_phase1(bool& marked_for_deopt,
@@ -93,4 +109,12 @@
bool doHeapRegion(HeapRegion* hr);
};
+// G1ArchiveRegionMap is a boolean array used to mark G1 regions as
+// archive regions. This allows a quick check for whether an object
+// should not be marked because it is in an archive region.
+class G1ArchiveRegionMap : public G1BiasedMappedArray<bool> {
+protected:
+ bool default_value() const { return false; }
+};
+
#endif // SHARE_VM_GC_G1_G1MARKSWEEP_HPP
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -51,7 +51,7 @@
_worker_id = par_scan_state->queue_num();
assert(_worker_id < ParallelGCThreads,
- err_msg("The given worker id %u must be less than the number of threads " UINTX_FORMAT, _worker_id, ParallelGCThreads));
+ err_msg("The given worker id %u must be less than the number of threads %u", _worker_id, ParallelGCThreads));
}
// Generate G1 specialized oop_oop_iterate functions.
--- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -627,7 +627,7 @@
void G1RemSet::prepare_for_verify() {
if (G1HRRSFlushLogBuffersOnVerify &&
(VerifyBeforeGC || VerifyAfterGC)
- && (!_g1->full_collection() || G1VerifyRSetsDuringFullGC)) {
+ && (!_g1->collector_state()->full_collection() || G1VerifyRSetsDuringFullGC)) {
cleanupHRRS();
_g1->set_refine_cte_cl_concurrency(false);
if (SafepointSynchronize::is_at_safepoint()) {
--- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -30,6 +30,7 @@
#include "gc/g1/bufferingOopClosure.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorPolicy.hpp"
+#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
#include "gc/g1/g1RemSet.inline.hpp"
#include "gc/g1/g1RootProcessor.hpp"
@@ -199,7 +200,7 @@
// as implicitly live).
{
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::SATBFiltering, worker_i);
- if (!_process_strong_tasks->is_task_claimed(G1RP_PS_filter_satb_buffers) && _g1h->mark_in_progress()) {
+ if (!_process_strong_tasks->is_task_claimed(G1RP_PS_filter_satb_buffers) && _g1h->collector_state()->mark_in_progress()) {
JavaThread::satb_mark_queue_set().filter_thread_buffers();
}
}
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -23,12 +23,14 @@
*/
#include "precompiled.hpp"
+#include "classfile/stringTable.hpp"
#include "gc/g1/g1Log.hpp"
#include "gc/g1/g1StringDedup.hpp"
#include "gc/g1/g1StringDedupQueue.hpp"
#include "gc/g1/g1StringDedupTable.hpp"
#include "gc/g1/g1StringDedupThread.hpp"
#include "gc/g1/suspendibleThreadSet.hpp"
+#include "oops/oop.inline.hpp"
#include "runtime/atomic.inline.hpp"
G1StringDedupThread* G1StringDedupThread::_thread = NULL;
@@ -55,11 +57,36 @@
return _thread;
}
+class G1StringDedupSharedClosure: public OopClosure {
+ private:
+ G1StringDedupStat& _stat;
+
+ public:
+ G1StringDedupSharedClosure(G1StringDedupStat& stat) : _stat(stat) {}
+
+ virtual void do_oop(oop* p) { ShouldNotReachHere(); }
+ virtual void do_oop(narrowOop* p) {
+ oop java_string = oopDesc::load_decode_heap_oop(p);
+ G1StringDedupTable::deduplicate(java_string, _stat);
+ }
+};
+
+// The CDS archive does not include the string dedupication table. Only the string
+// table is saved in the archive. The shared strings from CDS archive need to be
+// added to the string dedupication table before deduplication occurs. That is
+// done in the begining of the G1StringDedupThread (see G1StringDedupThread::run()
+// below).
+void G1StringDedupThread::deduplicate_shared_strings(G1StringDedupStat& stat) {
+ G1StringDedupSharedClosure sharedStringDedup(stat);
+ StringTable::shared_oops_do(&sharedStringDedup);
+}
+
void G1StringDedupThread::run() {
G1StringDedupStat total_stat;
initialize_in_thread();
wait_for_universe_init();
+ deduplicate_shared_strings(total_stat);
// Main loop
for (;;) {
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupThread.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -52,6 +52,8 @@
static G1StringDedupThread* thread();
virtual void run();
+
+ void deduplicate_shared_strings(G1StringDedupStat& stat);
};
#endif // SHARE_VM_GC_G1_G1STRINGDEDUPTHREAD_HPP
--- a/hotspot/src/share/vm/gc/g1/g1_globals.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1_globals.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -25,8 +25,14 @@
#include "precompiled.hpp"
#include "gc/g1/g1_globals.hpp"
-G1_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_EXPERIMENTAL_FLAG, \
+G1_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
+ MATERIALIZE_PD_DEVELOPER_FLAG, \
+ MATERIALIZE_PRODUCT_FLAG, \
+ MATERIALIZE_PD_PRODUCT_FLAG, \
+ MATERIALIZE_DIAGNOSTIC_FLAG, \
+ MATERIALIZE_EXPERIMENTAL_FLAG, \
MATERIALIZE_NOTPRODUCT_FLAG, \
- MATERIALIZE_MANAGEABLE_FLAG, MATERIALIZE_PRODUCT_RW_FLAG)
+ MATERIALIZE_MANAGEABLE_FLAG, \
+ MATERIALIZE_PRODUCT_RW_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
--- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -30,16 +30,19 @@
// Defines all globals flags used by the garbage-first compiler.
//
-#define G1_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, manageable, product_rw) \
+#define G1_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, manageable, product_rw, range, constraint) \
\
product(uintx, G1ConfidencePercent, 50, \
"Confidence level for MMU/pause predictions") \
+ range(0, 100) \
\
develop(intx, G1MarkingOverheadPercent, 0, \
"Overhead of concurrent marking") \
+ range(0, 100) \
\
develop(intx, G1MarkingVerboseLevel, 0, \
"Level (0-4) of verboseness of the marking code") \
+ range(0, 4) \
\
develop(bool, G1TraceMarkStackOverflow, false, \
"If true, extra debugging code for CM restart for ovflw.") \
@@ -68,10 +71,12 @@
product(double, G1ConcMarkStepDurationMillis, 10.0, \
"Target duration of individual concurrent marking steps " \
"in milliseconds.") \
+ range(1.0, (double)max_uintx) \
\
product(intx, G1RefProcDrainInterval, 10, \
"The number of discovered reference objects to process before " \
"draining concurrent marking work queues.") \
+ range(1, max_intx) \
\
experimental(bool, G1UseConcMarkReferenceProcessing, true, \
"If true, enable reference discovery during concurrent " \
@@ -89,9 +94,11 @@
"the percentage of retained entries is over this threshold " \
"the buffer will be enqueued for processing. A value of 0 " \
"specifies that mutator threads should not do such filtering.") \
+ range(0, 100) \
\
experimental(intx, G1ExpandByPercentOfAvailable, 20, \
"When expanding, % of uncommitted space to claim.") \
+ range(0, 100) \
\
develop(bool, G1RSBarrierRegionFilter, true, \
"If true, generate region filtering code in RS barrier") \
@@ -138,9 +145,11 @@
\
product(size_t, G1ConcRSLogCacheSize, 10, \
"Log base 2 of the length of conc RS hot-card cache.") \
+ range(0, 27) \
\
product(uintx, G1ConcRSHotCardLimit, 4, \
"The threshold that defines (>=) a hot card.") \
+ range(0, max_jubyte) \
\
develop(intx, G1RSetRegionEntriesBase, 256, \
"Max number of regions in a fine-grain table per MB.") \
@@ -183,6 +192,7 @@
product(uintx, G1ReservePercent, 10, \
"It determines the minimum reserve we should have in the heap " \
"to minimize the probability of promotion failure.") \
+ range(0, 100) \
\
diagnostic(bool, G1PrintHeapRegions, false, \
"If set G1 will print information on which regions are being " \
@@ -238,22 +248,27 @@
"The number of times we'll force an overflow during " \
"concurrent marking") \
\
+ experimental(uintx, G1MaxNewSizePercent, 60, \
+ "Percentage (0-100) of the heap size to use as default " \
+ " maximum young gen size.") \
+ range(0, 100) \
+ constraint(G1MaxNewSizePercentConstraintFunc) \
+ \
experimental(uintx, G1NewSizePercent, 5, \
"Percentage (0-100) of the heap size to use as default " \
"minimum young gen size.") \
- \
- experimental(uintx, G1MaxNewSizePercent, 60, \
- "Percentage (0-100) of the heap size to use as default " \
- " maximum young gen size.") \
+ constraint(G1NewSizePercentConstraintFunc) \
\
experimental(uintx, G1MixedGCLiveThresholdPercent, 85, \
"Threshold for regions to be considered for inclusion in the " \
"collection set of mixed GCs. " \
"Regions with live bytes exceeding this will not be collected.") \
+ range(0, 100) \
\
product(uintx, G1HeapWastePercent, 5, \
"Amount of space, expressed as a percentage of the heap size, " \
"that G1 is willing not to collect to avoid expensive GCs.") \
+ range(0, 100) \
\
product(uintx, G1MixedGCCountTarget, 8, \
"The target number of mixed GCs after a marking cycle.") \
@@ -272,6 +287,7 @@
experimental(uintx, G1OldCSetRegionThresholdPercent, 10, \
"An upper bound for the number of old CSet regions expressed " \
"as a percentage of the heap size.") \
+ range(0, 100) \
\
experimental(ccstr, G1LogLevel, NULL, \
"Log level for G1 logging: fine, finer, finest") \
@@ -314,6 +330,16 @@
develop(bool, G1VerifyBitmaps, false, \
"Verifies the consistency of the marking bitmaps")
-G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG)
+G1_FLAGS(DECLARE_DEVELOPER_FLAG, \
+ DECLARE_PD_DEVELOPER_FLAG, \
+ DECLARE_PRODUCT_FLAG, \
+ DECLARE_PD_PRODUCT_FLAG, \
+ DECLARE_DIAGNOSTIC_FLAG, \
+ DECLARE_EXPERIMENTAL_FLAG, \
+ DECLARE_NOTPRODUCT_FLAG, \
+ DECLARE_MANAGEABLE_FLAG, \
+ DECLARE_PRODUCT_RW_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
#endif // SHARE_VM_GC_G1_G1_GLOBALS_HPP
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -103,6 +103,10 @@
return HeapRegionBounds::max_size();
}
+size_t HeapRegion::min_region_size_in_words() {
+ return HeapRegionBounds::min_size() >> LogHeapWordSize;
+}
+
void HeapRegion::setup_heap_region_size(size_t initial_heap_size, size_t max_heap_size) {
size_t region_size = G1HeapRegionSize;
if (FLAG_IS_DEFAULT(G1HeapRegionSize)) {
@@ -711,12 +715,12 @@
_n_failures++;
}
- if (!_g1h->full_collection() || G1VerifyRSetsDuringFullGC) {
+ if (!_g1h->collector_state()->full_collection() || G1VerifyRSetsDuringFullGC) {
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
HeapRegion* to = _g1h->heap_region_containing(obj);
if (from != NULL && to != NULL &&
from != to &&
- !to->is_humongous()) {
+ !to->is_pinned()) {
jbyte cv_obj = *_bs->byte_for_const(_containing_obj);
jbyte cv_field = *_bs->byte_for_const(p);
const jbyte dirty = CardTableModRefBS::dirty_card_val();
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -331,6 +331,7 @@
}
static size_t max_region_size();
+ static size_t min_region_size_in_words();
// It sets up the heap region size (GrainBytes / GrainWords), as
// well as other related fields that are based on the heap region
@@ -417,6 +418,15 @@
bool is_old() const { return _type.is_old(); }
+ // A pinned region contains objects which are not moved by garbage collections.
+ // Humongous regions and archive regions are pinned.
+ bool is_pinned() const { return _type.is_pinned(); }
+
+ // An archive region is a pinned region, also tagged as old, which
+ // should not be marked during mark/sweep. This allows the address
+ // space to be shared by JVM instances.
+ bool is_archive() const { return _type.is_archive(); }
+
// For a humongous region, region in which it starts.
HeapRegion* humongous_start_region() const {
return _humongous_start_region;
@@ -670,6 +680,8 @@
void set_old() { _type.set_old(); }
+ void set_archive() { _type.set_archive(); }
+
// Determine if an object has been allocated since the last
// mark performed by the collector. This returns true iff the object
// is within the unmarked area of the region.
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -278,6 +278,55 @@
return num_regions;
}
+uint HeapRegionManager::find_highest_free(bool* expanded) {
+ // Loop downwards from the highest region index, looking for an
+ // entry which is either free or not yet committed. If not yet
+ // committed, expand_at that index.
+ uint curr = max_length() - 1;
+ while (true) {
+ HeapRegion *hr = _regions.get_by_index(curr);
+ if (hr == NULL) {
+ uint res = expand_at(curr, 1);
+ if (res == 1) {
+ *expanded = true;
+ return curr;
+ }
+ } else {
+ if (hr->is_free()) {
+ *expanded = false;
+ return curr;
+ }
+ }
+ if (curr == 0) {
+ return G1_NO_HRM_INDEX;
+ }
+ curr--;
+ }
+}
+
+bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* commit_count) {
+ size_t commits = 0;
+ uint start_index = (uint)_regions.get_index_by_address(range.start());
+ uint last_index = (uint)_regions.get_index_by_address(range.last());
+
+ // Ensure that each G1 region in the range is free, returning false if not.
+ // Commit those that are not yet available, and keep count.
+ for (uint curr_index = start_index; curr_index <= last_index; curr_index++) {
+ if (!is_available(curr_index)) {
+ commits++;
+ expand_at(curr_index, 1);
+ }
+ HeapRegion* curr_region = _regions.get_by_index(curr_index);
+ if (!curr_region->is_free()) {
+ return false;
+ }
+ }
+
+ allocate_free_regions_starting_at(start_index, (last_index - start_index) + 1);
+ *commit_count = commits;
+ return true;
+}
+
void HeapRegionManager::par_iterate(HeapRegionClosure* blk, uint worker_id, HeapRegionClaimer* hrclaimer, bool concurrent) const {
const uint start_index = hrclaimer->start_region_for_worker(worker_id);
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -221,6 +221,16 @@
HeapRegion* next_region_in_heap(const HeapRegion* r) const;
+ // Find the highest free or uncommitted region in the reserved heap,
+ // and if uncommitted, commit it. If none are available, return G1_NO_HRM_INDEX.
+ // Set the 'expanded' boolean true if a new region was committed.
+ uint find_highest_free(bool* expanded);
+
+ // Allocate the regions that contain the address range specified, committing the
+ // regions if necessary. Return false if any of the regions is already committed
+ // and not free, and return the number of regions newly committed in commit_count.
+ bool allocate_containing_regions(MemRegion range, size_t* commit_count);
+
// Apply blk->doHeapRegion() on all committed regions in address order,
// terminating the iteration early if doHeapRegion() returns true.
void iterate(HeapRegionClosure* blk) const;
--- a/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionRemSet.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -817,7 +817,7 @@
// This can be done by either mutator threads together with the
// concurrent refinement threads or GC threads.
uint HeapRegionRemSet::num_par_rem_sets() {
- return MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), (uint)ParallelGCThreads);
+ return MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads);
}
HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
--- a/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionSet.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -42,7 +42,8 @@
assert(hr->is_humongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrm_index(), name()));
assert(hr->is_free() == regions_free(), err_msg("Wrong free state for region %u and set %s", hr->hrm_index(), name()));
assert(!hr->is_free() || hr->is_empty(), err_msg("Free region %u is not empty for set %s", hr->hrm_index(), name()));
- assert(!hr->is_empty() || hr->is_free(), err_msg("Empty region %u is not free for set %s", hr->hrm_index(), name()));
+ assert(!hr->is_empty() || hr->is_free() || hr->is_archive(),
+ err_msg("Empty region %u is not free or archive for set %s", hr->hrm_index(), name()));
assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrm_index()));
}
#endif
--- a/hotspot/src/share/vm/gc/g1/heapRegionType.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionType.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -33,6 +33,7 @@
case StartsHumongousTag:
case ContinuesHumongousTag:
case OldTag:
+ case ArchiveTag:
return true;
}
return false;
@@ -47,6 +48,7 @@
case StartsHumongousTag: return "HUMS";
case ContinuesHumongousTag: return "HUMC";
case OldTag: return "OLD";
+ case ArchiveTag: return "ARC";
}
ShouldNotReachHere();
// keep some compilers happy
@@ -62,6 +64,7 @@
case StartsHumongousTag: return "HS";
case ContinuesHumongousTag: return "HC";
case OldTag: return "O";
+ case ArchiveTag: return "A";
}
ShouldNotReachHere();
// keep some compilers happy
--- a/hotspot/src/share/vm/gc/g1/heapRegionType.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/g1/heapRegionType.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -44,15 +44,18 @@
//
// 0000 0 [ 0] Free
//
- // 0001 0 Young Mask
+ // 0001 0 [ 2] Young Mask
// 0001 0 [ 2] Eden
// 0001 1 [ 3] Survivor
//
- // 0010 0 Humongous Mask
- // 0010 0 [ 4] Starts Humongous
- // 0010 1 [ 5] Continues Humongous
+ // 0010 0 [ 4] Humongous Mask
+ // 0100 0 [ 8] Pinned Mask
+ // 0110 0 [12] Starts Humongous
+ // 0110 1 [13] Continues Humongous
//
- // 01000 [ 8] Old
+ // 1000 0 [16] Old Mask
+ //
+ // 1100 0 [24] Archive
typedef enum {
FreeTag = 0,
@@ -61,10 +64,14 @@
SurvTag = YoungMask + 1,
HumongousMask = 4,
- StartsHumongousTag = HumongousMask,
- ContinuesHumongousTag = HumongousMask + 1,
+ PinnedMask = 8,
+ StartsHumongousTag = HumongousMask | PinnedMask,
+ ContinuesHumongousTag = HumongousMask | PinnedMask + 1,
- OldTag = 8
+ OldMask = 16,
+ OldTag = OldMask,
+
+ ArchiveTag = PinnedMask | OldMask
} Tag;
volatile Tag _tag;
@@ -108,7 +115,13 @@
bool is_starts_humongous() const { return get() == StartsHumongousTag; }
bool is_continues_humongous() const { return get() == ContinuesHumongousTag; }
- bool is_old() const { return get() == OldTag; }
+ bool is_archive() const { return get() == ArchiveTag; }
+
+ // is_old regions may or may not also be pinned
+ bool is_old() const { return (get() & OldMask) != 0; }
+
+ // is_pinned regions may be archive or humongous
+ bool is_pinned() const { return (get() & PinnedMask) != 0; }
// Setters
@@ -123,6 +136,8 @@
void set_old() { set(OldTag); }
+ void set_archive() { set_from(ArchiveTag, FreeTag); }
+
// Misc
const char* get_str() const;
--- a/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/gcTaskManager.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -484,12 +484,12 @@
assert(!all_workers_active() || active_workers() == ParallelGCThreads,
err_msg("all_workers_active() is incorrect: "
- "active %d ParallelGCThreads " UINTX_FORMAT, active_workers(),
+ "active %d ParallelGCThreads %u", active_workers(),
ParallelGCThreads));
if (TraceDynamicGCThreads) {
gclog_or_tty->print_cr("GCTaskManager::set_active_gang(): "
"all_workers_active() %d workers %d "
- "active %d ParallelGCThreads " UINTX_FORMAT,
+ "active %d ParallelGCThreads %u",
all_workers_active(), workers(), active_workers(),
ParallelGCThreads);
}
--- a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -255,7 +255,7 @@
which_stack_index = which;
assert(manager->active_workers() == ParallelGCThreads,
err_msg("all_workers_active has been incorrectly set: "
- " active %d ParallelGCThreads " UINTX_FORMAT, manager->active_workers(),
+ " active %d ParallelGCThreads %u", manager->active_workers(),
ParallelGCThreads));
} else {
which_stack_index = ParCompactionManager::pop_recycled_stack_index();
@@ -334,7 +334,7 @@
which_stack_index = which;
assert(manager->active_workers() == ParallelGCThreads,
err_msg("all_workers_active has been incorrectly set: "
- " active %d ParallelGCThreads " UINTX_FORMAT, manager->active_workers(),
+ " active %d ParallelGCThreads %u", manager->active_workers(),
ParallelGCThreads));
} else {
which_stack_index = stack_index();
--- a/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psAdaptiveSizePolicy.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1304,7 +1304,7 @@
size_t survived_guess = survived + promoted;
_avg_survived->sample(survived_guess);
}
- avg_promoted()->sample(promoted + _avg_pretenured->padded_average());
+ avg_promoted()->sample(promoted);
if (PrintAdaptiveSizePolicy) {
gclog_or_tty->print_cr(
--- a/hotspot/src/share/vm/gc/parallel/psCompactionManager.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psCompactionManager.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -170,8 +170,8 @@
}
ParCompactionManager*
-ParCompactionManager::gc_thread_compaction_manager(int index) {
- assert(index >= 0 && index < (int)ParallelGCThreads, "index out of range");
+ParCompactionManager::gc_thread_compaction_manager(uint index) {
+ assert(index < ParallelGCThreads, "index out of range");
assert(_manager_array != NULL, "Sanity");
return _manager_array[index];
}
--- a/hotspot/src/share/vm/gc/parallel/psCompactionManager.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psCompactionManager.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -133,7 +133,7 @@
RegionTaskQueue* region_stack() { return _region_stack; }
void set_region_stack(RegionTaskQueue* v) { _region_stack = v; }
- inline static ParCompactionManager* manager_array(int index);
+ inline static ParCompactionManager* manager_array(uint index);
inline static RegionTaskQueue* region_list(int index) {
return _region_list[index];
@@ -177,7 +177,7 @@
void follow_class_loader(ClassLoaderData* klass);
// Access function for compaction managers
- static ParCompactionManager* gc_thread_compaction_manager(int index);
+ static ParCompactionManager* gc_thread_compaction_manager(uint index);
static bool steal(int queue_num, int* seed, oop& t);
static bool steal_objarray(int queue_num, int* seed, ObjArrayTask& t);
@@ -229,10 +229,9 @@
};
};
-inline ParCompactionManager* ParCompactionManager::manager_array(int index) {
+inline ParCompactionManager* ParCompactionManager::manager_array(uint index) {
assert(_manager_array != NULL, "access of NULL manager_array");
- assert(index >= 0 && index <= (int)ParallelGCThreads,
- "out of range manager_array access");
+ assert(index <= ParallelGCThreads, "out of range manager_array access");
return _manager_array[index];
}
--- a/hotspot/src/share/vm/gc/parallel/psOldGen.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psOldGen.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -199,7 +199,7 @@
// Allocations in the old generation need to be reported
if (res != NULL) {
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
- heap->size_policy()->tenured_allocation(word_size);
+ heap->size_policy()->tenured_allocation(word_size * HeapWordSize);
}
return res;
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -832,10 +832,10 @@
_ref_processor =
new ReferenceProcessor(mr, // span
ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing
- (uint) ParallelGCThreads, // mt processing degree
- true, // mt discovery
- (uint) ParallelGCThreads, // mt discovery degree
- true, // atomic_discovery
+ ParallelGCThreads, // mt processing degree
+ true, // mt discovery
+ ParallelGCThreads, // mt discovery degree
+ true, // atomic_discovery
&_is_alive_closure); // non-header is alive closure
_counters = new CollectorCounters("PSParallelCompact", 1);
--- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -75,8 +75,8 @@
return PSScavenge::should_scavenge(p, check_to_space);
}
-PSPromotionManager* PSPromotionManager::gc_thread_promotion_manager(int index) {
- assert(index >= 0 && index < (int)ParallelGCThreads, "index out of range");
+PSPromotionManager* PSPromotionManager::gc_thread_promotion_manager(uint index) {
+ assert(index < ParallelGCThreads, "index out of range");
assert(_manager_array != NULL, "Sanity");
return &_manager_array[index];
}
--- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -90,7 +90,7 @@
static PSOldGen* old_gen() { return _old_gen; }
static MutableSpace* young_space() { return _young_space; }
- inline static PSPromotionManager* manager_array(int index);
+ inline static PSPromotionManager* manager_array(uint index);
template <class T> inline void claim_or_forward_internal_depth(T* p);
// On the task queues we push reference locations as well as
@@ -154,7 +154,7 @@
static void pre_scavenge();
static bool post_scavenge(YoungGCTracer& gc_tracer);
- static PSPromotionManager* gc_thread_promotion_manager(int index);
+ static PSPromotionManager* gc_thread_promotion_manager(uint index);
static PSPromotionManager* vm_thread_promotion_manager();
static bool steal_depth(int queue_num, int* seed, StarTask& t);
--- a/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psPromotionManager.inline.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -33,9 +33,9 @@
#include "gc/shared/taskqueue.inline.hpp"
#include "oops/oop.inline.hpp"
-inline PSPromotionManager* PSPromotionManager::manager_array(int index) {
+inline PSPromotionManager* PSPromotionManager::manager_array(uint index) {
assert(_manager_array != NULL, "access of NULL manager_array");
- assert(index >= 0 && index <= (int)ParallelGCThreads, "out of range manager_array access");
+ assert(index <= ParallelGCThreads, "out of range manager_array access");
return &_manager_array[index];
}
--- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -845,9 +845,9 @@
_ref_processor =
new ReferenceProcessor(mr, // span
ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing
- (uint) ParallelGCThreads, // mt processing degree
+ ParallelGCThreads, // mt processing degree
true, // mt discovery
- (uint) ParallelGCThreads, // mt discovery degree
+ ParallelGCThreads, // mt discovery degree
true, // atomic_discovery
NULL); // header provides liveness info
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -58,11 +58,13 @@
// Methods of protected closure types.
-DefNewGeneration::IsAliveClosure::IsAliveClosure(Generation* g) : _g(g) {
- assert(g->level() == 0, "Optimized for youngest gen.");
+DefNewGeneration::IsAliveClosure::IsAliveClosure(Generation* young_gen) : _young_gen(young_gen) {
+ assert(_young_gen->kind() == Generation::ParNew ||
+ _young_gen->kind() == Generation::DefNew, "Expected the young generation here");
}
+
bool DefNewGeneration::IsAliveClosure::do_object_b(oop p) {
- return (HeapWord*)p >= _g->reserved().end() || p->is_forwarded();
+ return (HeapWord*)p >= _young_gen->reserved().end() || p->is_forwarded();
}
DefNewGeneration::KeepAliveClosure::
@@ -85,39 +87,38 @@
void DefNewGeneration::FastKeepAliveClosure::do_oop(narrowOop* p) { DefNewGeneration::FastKeepAliveClosure::do_oop_work(p); }
DefNewGeneration::EvacuateFollowersClosure::
-EvacuateFollowersClosure(GenCollectedHeap* gch, int level,
- ScanClosure* cur, ScanClosure* older) :
- _gch(gch), _level(level),
- _scan_cur_or_nonheap(cur), _scan_older(older)
+EvacuateFollowersClosure(GenCollectedHeap* gch,
+ ScanClosure* cur,
+ ScanClosure* older) :
+ _gch(gch), _scan_cur_or_nonheap(cur), _scan_older(older)
{}
void DefNewGeneration::EvacuateFollowersClosure::do_void() {
do {
- _gch->oop_since_save_marks_iterate(_level, _scan_cur_or_nonheap,
- _scan_older);
- } while (!_gch->no_allocs_since_save_marks(_level));
+ _gch->oop_since_save_marks_iterate(GenCollectedHeap::YoungGen, _scan_cur_or_nonheap, _scan_older);
+ } while (!_gch->no_allocs_since_save_marks(GenCollectedHeap::YoungGen));
}
DefNewGeneration::FastEvacuateFollowersClosure::
-FastEvacuateFollowersClosure(GenCollectedHeap* gch, int level,
- DefNewGeneration* gen,
- FastScanClosure* cur, FastScanClosure* older) :
- _gch(gch), _level(level), _gen(gen),
- _scan_cur_or_nonheap(cur), _scan_older(older)
-{}
+FastEvacuateFollowersClosure(GenCollectedHeap* gch,
+ FastScanClosure* cur,
+ FastScanClosure* older) :
+ _gch(gch), _scan_cur_or_nonheap(cur), _scan_older(older)
+{
+ assert(_gch->young_gen()->kind() == Generation::DefNew, "Generation should be DefNew");
+ _gen = (DefNewGeneration*)_gch->young_gen();
+}
void DefNewGeneration::FastEvacuateFollowersClosure::do_void() {
do {
- _gch->oop_since_save_marks_iterate(_level, _scan_cur_or_nonheap,
- _scan_older);
- } while (!_gch->no_allocs_since_save_marks(_level));
+ _gch->oop_since_save_marks_iterate(GenCollectedHeap::YoungGen, _scan_cur_or_nonheap, _scan_older);
+ } while (!_gch->no_allocs_since_save_marks(GenCollectedHeap::YoungGen));
guarantee(_gen->promo_failure_scan_is_complete(), "Failed to finish scan");
}
ScanClosure::ScanClosure(DefNewGeneration* g, bool gc_barrier) :
OopsInKlassOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
{
- assert(_g->level() == 0, "Optimized for youngest generation");
_boundary = _g->reserved().end();
}
@@ -127,7 +128,6 @@
FastScanClosure::FastScanClosure(DefNewGeneration* g, bool gc_barrier) :
OopsInKlassOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
{
- assert(_g->level() == 0, "Optimized for youngest generation");
_boundary = _g->reserved().end();
}
@@ -168,7 +168,6 @@
ScanWeakRefClosure::ScanWeakRefClosure(DefNewGeneration* g) :
_g(g)
{
- assert(_g->level() == 0, "Optimized for youngest generation");
_boundary = _g->reserved().end();
}
@@ -186,9 +185,8 @@
DefNewGeneration::DefNewGeneration(ReservedSpace rs,
size_t initial_size,
- int level,
const char* policy)
- : Generation(rs, initial_size, level),
+ : Generation(rs, initial_size),
_promo_failure_drain_in_progress(false),
_should_allocate_from_space(false)
{
@@ -372,22 +370,18 @@
return success;
}
-
void DefNewGeneration::compute_new_size() {
- // This is called after a gc that includes the following generation
- // (which is required to exist.) So from-space will normally be empty.
+ // This is called after a GC that includes the old generation, so from-space
+ // will normally be empty.
// Note that we check both spaces, since if scavenge failed they revert roles.
- // If not we bail out (otherwise we would have to relocate the objects)
+ // If not we bail out (otherwise we would have to relocate the objects).
if (!from()->is_empty() || !to()->is_empty()) {
return;
}
- int next_level = level() + 1;
GenCollectedHeap* gch = GenCollectedHeap::heap();
- assert(next_level == 1, "DefNewGeneration must be a young gen");
- Generation* old_gen = gch->old_gen();
- size_t old_size = old_gen->capacity();
+ size_t old_size = gch->old_gen()->capacity();
size_t new_size_before = _virtual_space.committed_size();
size_t min_new_size = spec()->init_size();
size_t max_new_size = reserved().byte_size();
@@ -603,7 +597,7 @@
gch->rem_set()->prepare_for_younger_refs_iterate(false);
- assert(gch->no_allocs_since_save_marks(0),
+ assert(gch->no_allocs_since_save_marks(GenCollectedHeap::YoungGen),
"save marks have not been newly set.");
// Not very pretty.
@@ -619,11 +613,11 @@
false);
set_promo_failure_scan_stack_closure(&fsc_with_no_gc_barrier);
- FastEvacuateFollowersClosure evacuate_followers(gch, _level, this,
+ FastEvacuateFollowersClosure evacuate_followers(gch,
&fsc_with_no_gc_barrier,
&fsc_with_gc_barrier);
- assert(gch->no_allocs_since_save_marks(0),
+ assert(gch->no_allocs_since_save_marks(GenCollectedHeap::YoungGen),
"save marks have not been newly set.");
{
@@ -633,7 +627,7 @@
StrongRootsScope srs(0);
gch->gen_process_roots(&srs,
- _level,
+ GenCollectedHeap::YoungGen,
true, // Process younger gens, if any,
// as strong roots.
GenCollectedHeap::SO_ScavengeCodeCache,
@@ -870,8 +864,10 @@
void DefNewGeneration::contribute_scratch(ScratchBlock*& list, Generation* requestor,
size_t max_alloc_words) {
- if (requestor == this || _promotion_failed) return;
- assert(requestor->level() > level(), "DefNewGeneration must be youngest");
+ if (requestor == this || _promotion_failed) {
+ return;
+ }
+ assert(GenCollectedHeap::heap()->is_old_gen(requestor), "We should not call our own generation");
/* $$$ Assert this? "trace" is a "MarkSweep" function so that's not appropriate.
if (to_space->top() > to_space->bottom()) {
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -154,9 +154,9 @@
public: // was "protected" but caused compile error on win32
class IsAliveClosure: public BoolObjectClosure {
- Generation* _g;
+ Generation* _young_gen;
public:
- IsAliveClosure(Generation* g);
+ IsAliveClosure(Generation* young_gen);
bool do_object_b(oop p);
};
@@ -183,31 +183,28 @@
class EvacuateFollowersClosure: public VoidClosure {
GenCollectedHeap* _gch;
- int _level;
ScanClosure* _scan_cur_or_nonheap;
ScanClosure* _scan_older;
public:
- EvacuateFollowersClosure(GenCollectedHeap* gch, int level,
+ EvacuateFollowersClosure(GenCollectedHeap* gch,
ScanClosure* cur, ScanClosure* older);
void do_void();
};
class FastEvacuateFollowersClosure: public VoidClosure {
GenCollectedHeap* _gch;
- int _level;
DefNewGeneration* _gen;
FastScanClosure* _scan_cur_or_nonheap;
FastScanClosure* _scan_older;
public:
- FastEvacuateFollowersClosure(GenCollectedHeap* gch, int level,
- DefNewGeneration* gen,
+ FastEvacuateFollowersClosure(GenCollectedHeap* gch,
FastScanClosure* cur,
FastScanClosure* older);
void do_void();
};
public:
- DefNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level,
+ DefNewGeneration(ReservedSpace rs, size_t initial_byte_size,
const char* policy="Copy");
virtual void ref_processor_init();
--- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -36,6 +36,7 @@
#include "gc/shared/gcTrace.hpp"
#include "gc/shared/gcTraceTime.hpp"
#include "gc/shared/genCollectedHeap.hpp"
+#include "gc/shared/generation.hpp"
#include "gc/shared/genOopClosures.inline.hpp"
#include "gc/shared/modRefBarrierSet.hpp"
#include "gc/shared/referencePolicy.hpp"
@@ -53,8 +54,7 @@
#include "utilities/events.hpp"
#include "utilities/stack.inline.hpp"
-void GenMarkSweep::invoke_at_safepoint(int level, ReferenceProcessor* rp, bool clear_all_softrefs) {
- guarantee(level == 1, "We always collect both old and young.");
+void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_softrefs) {
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
GenCollectedHeap* gch = GenCollectedHeap::heap();
@@ -87,11 +87,11 @@
// Capture used regions for each generation that will be
// subject to collection, so that card table adjustments can
// be made intelligently (see clear / invalidate further below).
- gch->save_used_regions(level);
+ gch->save_used_regions();
allocate_stacks();
- mark_sweep_phase1(level, clear_all_softrefs);
+ mark_sweep_phase1(clear_all_softrefs);
mark_sweep_phase2();
@@ -99,7 +99,7 @@
COMPILER2_PRESENT(assert(DerivedPointerTable::is_active(), "Sanity"));
COMPILER2_PRESENT(DerivedPointerTable::set_active(false));
- mark_sweep_phase3(level);
+ mark_sweep_phase3();
mark_sweep_phase4();
@@ -184,8 +184,7 @@
_objarray_stack.clear(true);
}
-void GenMarkSweep::mark_sweep_phase1(int level,
- bool clear_all_softrefs) {
+void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
// Recursively traverse all live objects and mark them
GCTraceTime tm("phase 1", PrintGC && Verbose, true, _gc_timer, _gc_tracer->gc_id());
@@ -195,7 +194,6 @@
// use OopsInGenClosure constructor which takes a generation,
// as the Universe has not been created when the static constructors
// are run.
- assert(level == 1, "We don't use mark-sweep on young generations");
follow_root_closure.set_orig_generation(gch->old_gen());
// Need new claim bits before marking starts.
@@ -205,10 +203,10 @@
StrongRootsScope srs(1);
gch->gen_process_roots(&srs,
- level,
+ GenCollectedHeap::OldGen,
false, // Younger gens are not roots.
GenCollectedHeap::SO_None,
- GenCollectedHeap::StrongRootsOnly,
+ ClassUnloading,
&follow_root_closure,
&follow_root_closure,
&follow_cld_closure);
@@ -273,7 +271,7 @@
}
};
-void GenMarkSweep::mark_sweep_phase3(int level) {
+void GenMarkSweep::mark_sweep_phase3() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
// Adjust the pointers to reflect the new locations
@@ -286,14 +284,13 @@
// use OopsInGenClosure constructor which takes a generation,
// as the Universe has not been created when the static constructors
// are run.
- assert(level == 1, "We don't use mark-sweep on young generations.");
adjust_pointer_closure.set_orig_generation(gch->old_gen());
{
StrongRootsScope srs(1);
gch->gen_process_roots(&srs,
- level,
+ GenCollectedHeap::OldGen,
false, // Younger gens are not roots.
GenCollectedHeap::SO_AllCodeCache,
GenCollectedHeap::StrongAndWeakRoots,
--- a/hotspot/src/share/vm/gc/serial/genMarkSweep.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -31,17 +31,16 @@
friend class VM_MarkSweep;
friend class G1MarkSweep;
public:
- static void invoke_at_safepoint(int level, ReferenceProcessor* rp,
- bool clear_all_softrefs);
+ static void invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_softrefs);
private:
// Mark live objects
- static void mark_sweep_phase1(int level, bool clear_all_softrefs);
+ static void mark_sweep_phase1(bool clear_all_softrefs);
// Calculate new addresses
static void mark_sweep_phase2();
// Update pointers
- static void mark_sweep_phase3(int level);
+ static void mark_sweep_phase3();
// Move objects to new positions
static void mark_sweep_phase4();
--- a/hotspot/src/share/vm/gc/serial/markSweep.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/serial/markSweep.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -313,7 +313,7 @@
MarkSweep::IsAliveClosure MarkSweep::is_alive;
-bool MarkSweep::IsAliveClosure::do_object_b(oop p) { return p->is_gc_marked(); }
+bool MarkSweep::IsAliveClosure::do_object_b(oop p) { return p->is_gc_marked() || is_archive_object(p); }
MarkSweep::KeepAliveClosure MarkSweep::keep_alive;
--- a/hotspot/src/share/vm/gc/serial/markSweep.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/serial/markSweep.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -147,6 +147,9 @@
// Reference Processing
static ReferenceProcessor* const ref_processor() { return _ref_processor; }
+ // Archive Object handling
+ static inline bool is_archive_object(oop object);
+
static STWGCTimer* gc_timer() { return _gc_timer; }
static SerialOldTracer* gc_tracer() { return _gc_tracer; }
--- a/hotspot/src/share/vm/gc/serial/markSweep.inline.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/serial/markSweep.inline.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -37,6 +37,7 @@
#include "utilities/stack.inline.hpp"
#if INCLUDE_ALL_GCS
#include "gc/g1/g1StringDedup.hpp"
+#include "gc/g1/g1MarkSweep.hpp"
#endif // INCLUDE_ALL_GCS
inline void MarkSweep::mark_object(oop obj) {
@@ -57,6 +58,15 @@
}
}
+inline bool MarkSweep::is_archive_object(oop object) {
+#if INCLUDE_ALL_GCS
+ return (G1MarkSweep::archive_check_enabled() &&
+ G1MarkSweep::in_archive_range(object));
+#else
+ return false;
+#endif
+}
+
inline void MarkSweep::follow_klass(Klass* klass) {
oop op = klass->klass_holder();
MarkSweep::mark_and_push(&op);
@@ -74,7 +84,8 @@
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
- if (!obj->mark()->is_marked()) {
+ if (!obj->mark()->is_marked() &&
+ !is_archive_object(obj)) {
mark_object(obj);
follow_object(obj);
}
@@ -87,7 +98,8 @@
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
- if (!obj->mark()->is_marked()) {
+ if (!obj->mark()->is_marked() &&
+ !is_archive_object(obj)) {
mark_object(obj);
_marking_stack.push(obj);
}
@@ -111,15 +123,18 @@
assert(Universe::heap()->is_in(obj), "should be in heap");
oop new_obj = oop(obj->mark()->decode_pointer());
- assert(new_obj != NULL || // is forwarding ptr?
+ assert(is_archive_object(obj) || // no forwarding of archive objects
+ new_obj != NULL || // is forwarding ptr?
obj->mark() == markOopDesc::prototype() || // not gc marked?
(UseBiasedLocking && obj->mark()->has_bias_pattern()),
- // not gc marked?
+ // not gc marked?
"should be forwarded");
if (new_obj != NULL) {
- assert(Universe::heap()->is_in_reserved(new_obj),
- "should be in object space");
- oopDesc::encode_store_heap_oop_not_null(p, new_obj);
+ if (!is_archive_object(obj)) {
+ assert(Universe::heap()->is_in_reserved(new_obj),
+ "should be in object space");
+ oopDesc::encode_store_heap_oop_not_null(p, new_obj);
+ }
}
}
}
--- a/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -41,9 +41,9 @@
#endif
TenuredGeneration::TenuredGeneration(ReservedSpace rs,
- size_t initial_byte_size, int level,
+ size_t initial_byte_size,
GenRemSet* remset) :
- CardGeneration(rs, initial_byte_size, level, remset)
+ CardGeneration(rs, initial_byte_size, remset)
{
HeapWord* bottom = (HeapWord*) _virtual_space.low();
HeapWord* end = (HeapWord*) _virtual_space.high();
@@ -134,11 +134,12 @@
" capacity: " SIZE_FORMAT, used(), used_after_gc, capacity()));
}
-void TenuredGeneration::update_gc_stats(int current_level,
+void TenuredGeneration::update_gc_stats(Generation* current_generation,
bool full) {
- // If the next lower level(s) has been collected, gather any statistics
+ // If the young generation has been collected, gather any statistics
// that are of interest at this point.
- if (!full && (current_level + 1) == level()) {
+ bool current_is_young = GenCollectedHeap::heap()->is_young_gen(current_generation);
+ if (!full && current_is_young) {
// Calculate size of data promoted from the younger generations
// before doing the collection.
size_t used_before_gc = used();
@@ -192,7 +193,7 @@
SerialOldTracer* gc_tracer = GenMarkSweep::gc_tracer();
gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
- GenMarkSweep::invoke_at_safepoint(_level, ref_processor(), clear_all_soft_refs);
+ GenMarkSweep::invoke_at_safepoint(ref_processor(), clear_all_soft_refs);
gc_timer->register_gc_end();
--- a/hotspot/src/share/vm/gc/serial/tenuredGeneration.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/serial/tenuredGeneration.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -55,8 +55,9 @@
void assert_correct_size_change_locking();
public:
- TenuredGeneration(ReservedSpace rs, size_t initial_byte_size,
- int level, GenRemSet* remset);
+ TenuredGeneration(ReservedSpace rs,
+ size_t initial_byte_size,
+ GenRemSet* remset);
Generation::Name kind() { return Generation::MarkSweepCompact; }
@@ -120,7 +121,7 @@
// Statistics
- virtual void update_gc_stats(int level, bool full);
+ virtual void update_gc_stats(Generation* current_generation, bool full);
virtual bool promotion_attempt_is_safe(size_t max_promoted_in_bytes) const;
--- a/hotspot/src/share/vm/gc/shared/cardGeneration.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/cardGeneration.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -35,10 +35,10 @@
#include "memory/memRegion.hpp"
#include "runtime/java.hpp"
-CardGeneration::CardGeneration(ReservedSpace rs, size_t initial_byte_size,
- int level,
+CardGeneration::CardGeneration(ReservedSpace rs,
+ size_t initial_byte_size,
GenRemSet* remset) :
- Generation(rs, initial_byte_size, level), _rs(remset),
+ Generation(rs, initial_byte_size), _rs(remset),
_shrink_factor(0), _min_heap_delta_bytes(), _capacity_at_prologue(),
_used_at_prologue()
{
--- a/hotspot/src/share/vm/gc/shared/cardGeneration.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/cardGeneration.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -52,8 +52,7 @@
size_t _capacity_at_prologue;
size_t _used_at_prologue;
- CardGeneration(ReservedSpace rs, size_t initial_byte_size, int level,
- GenRemSet* remset);
+ CardGeneration(ReservedSpace rs, size_t initial_byte_size, GenRemSet* remset);
virtual void assert_correct_size_change_locking() = 0;
--- a/hotspot/src/share/vm/gc/shared/cardTableRS.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/cardTableRS.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -104,7 +104,9 @@
void CardTableRS::younger_refs_iterate(Generation* g,
OopsInGenClosure* blk,
uint n_threads) {
- _last_cur_val_in_gen[g->level()+1] = cur_youngergen_card_val();
+ // The indexing in this array is slightly odd. We want to access
+ // the old generation record here, which is at index 2.
+ _last_cur_val_in_gen[2] = cur_youngergen_card_val();
g->younger_refs_iterate(blk, n_threads);
}
@@ -300,7 +302,8 @@
}
void CardTableRS::clear_into_younger(Generation* old_gen) {
- assert(old_gen->level() == 1, "Should only be called for the old generation");
+ assert(GenCollectedHeap::heap()->is_old_gen(old_gen),
+ "Should only be called for the old generation");
// The card tables for the youngest gen need never be cleared.
// There's a bit of subtlety in the clear() and invalidate()
// methods that we exploit here and in invalidate_or_clear()
@@ -311,7 +314,8 @@
}
void CardTableRS::invalidate_or_clear(Generation* old_gen) {
- assert(old_gen->level() == 1, "Should only be called for the old generation");
+ assert(GenCollectedHeap::heap()->is_old_gen(old_gen),
+ "Should only be called for the old generation");
// Invalidate the cards for the currently occupied part of
// the old generation and clear the cards for the
// unoccupied part of the generation (if any, making use
@@ -377,7 +381,9 @@
VerifyCTGenClosure(CardTableRS* ct) : _ct(ct) {}
void do_generation(Generation* gen) {
// Skip the youngest generation.
- if (gen->level() == 0) return;
+ if (GenCollectedHeap::heap()->is_young_gen(gen)) {
+ return;
+ }
// Normally, we're interested in pointers to younger generations.
VerifyCTSpaceClosure blk(_ct, gen->reserved().start());
gen->space_iterate(&blk, true);
--- a/hotspot/src/share/vm/gc/shared/cardTableRS.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/cardTableRS.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -76,9 +76,8 @@
// An array that contains, for each generation, the card table value last
// used as the current value for a younger_refs_do iteration of that
- // portion of the table. (The perm gen is index 0; other gens are at
- // their level plus 1. They youngest gen is in the table, but will
- // always have the value "clean_card".)
+ // portion of the table. The perm gen is index 0. The young gen is index 1,
+ // but will always have the value "clean_card". The old gen is index 2.
jbyte* _last_cur_val_in_gen;
jbyte _cur_youngergen_card_val;
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -88,9 +88,6 @@
static int _fire_out_of_memory_count;
#endif
- // Used for filler objects (static, but initialized in ctor).
- static size_t _filler_array_max_size;
-
GCHeapLog* _gc_heap_log;
// Used in support of ReduceInitialCardMarks; only consulted if COMPILER2 is being used
@@ -102,6 +99,9 @@
BarrierSet* _barrier_set;
bool _is_gc_active;
+ // Used for filler objects (static, but initialized in ctor).
+ static size_t _filler_array_max_size;
+
unsigned int _total_collections; // ... started
unsigned int _total_full_collections; // ... started
NOT_PRODUCT(volatile size_t _promotion_failure_alot_count;)
--- a/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -746,11 +746,11 @@
return result; // Could be null if we are out of space.
} else if (!gch->incremental_collection_will_fail(false /* don't consult_young */)) {
// Do an incremental collection.
- gch->do_collection(false /* full */,
- false /* clear_all_soft_refs */,
- size /* size */,
- is_tlab /* is_tlab */,
- number_of_generations() - 1 /* max_level */);
+ gch->do_collection(false, // full
+ false, // clear_all_soft_refs
+ size, // size
+ is_tlab, // is_tlab
+ GenCollectedHeap::OldGen); // max_generation
} else {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print(" :: Trying full because partial may fail :: ");
@@ -759,11 +759,11 @@
// for the original code and why this has been simplified
// with from-space allocation criteria modified and
// such allocation moved out of the safepoint path.
- gch->do_collection(true /* full */,
- false /* clear_all_soft_refs */,
- size /* size */,
- is_tlab /* is_tlab */,
- number_of_generations() - 1 /* max_level */);
+ gch->do_collection(true, // full
+ false, // clear_all_soft_refs
+ size, // size
+ is_tlab, // is_tlab
+ GenCollectedHeap::OldGen); // max_generation
}
result = gch->attempt_allocation(size, is_tlab, false /*first_only*/);
@@ -787,11 +787,11 @@
{
UIntXFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted
- gch->do_collection(true /* full */,
- true /* clear_all_soft_refs */,
- size /* size */,
- is_tlab /* is_tlab */,
- number_of_generations() - 1 /* max_level */);
+ gch->do_collection(true, // full
+ true, // clear_all_soft_refs
+ size, // size
+ is_tlab, // is_tlab
+ GenCollectedHeap::OldGen); // max_generation
}
result = gch->attempt_allocation(size, is_tlab, false /* first_only */);
--- a/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/collectorPolicy.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -261,8 +261,6 @@
size_t initial_old_size() { return _initial_old_size; }
size_t max_old_size() { return _max_old_size; }
- int number_of_generations() { return 2; }
-
GenerationSpec* young_gen_spec() const {
assert(_young_gen_spec != NULL, "_young_gen_spec should have been initialized");
return _young_gen_spec;
--- a/hotspot/src/share/vm/gc/shared/gcHeapSummary.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/gcHeapSummary.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -78,11 +78,13 @@
class GCHeapSummary;
class PSHeapSummary;
+class G1HeapSummary;
class GCHeapSummaryVisitor {
public:
virtual void visit(const GCHeapSummary* heap_summary) const = 0;
virtual void visit(const PSHeapSummary* heap_summary) const {}
+ virtual void visit(const G1HeapSummary* heap_summary) const {}
};
class GCHeapSummary : public StackObj {
@@ -125,6 +127,22 @@
}
};
+class G1HeapSummary : public GCHeapSummary {
+ size_t _edenUsed;
+ size_t _edenCapacity;
+ size_t _survivorUsed;
+ public:
+ G1HeapSummary(VirtualSpaceSummary& heap_space, size_t heap_used, size_t edenUsed, size_t edenCapacity, size_t survivorUsed) :
+ GCHeapSummary(heap_space, heap_used), _edenUsed(edenUsed), _edenCapacity(edenCapacity), _survivorUsed(survivorUsed) { }
+ const size_t edenUsed() const { return _edenUsed; }
+ const size_t edenCapacity() const { return _edenCapacity; }
+ const size_t survivorUsed() const { return _survivorUsed; }
+
+ virtual void accept(GCHeapSummaryVisitor* visitor) const {
+ visitor->visit(this);
+ }
+};
+
class MetaspaceSummary : public StackObj {
size_t _capacity_until_GC;
MetaspaceSizes _meta_space;
--- a/hotspot/src/share/vm/gc/shared/gcTrace.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/gcTrace.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -44,6 +44,7 @@
class MetaspaceChunkFreeListSummary;
class MetaspaceSummary;
class PSHeapSummary;
+class G1HeapSummary;
class ReferenceProcessorStats;
class TimePartitions;
class BoolObjectClosure;
--- a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -263,6 +263,20 @@
}
}
+ void visit(const G1HeapSummary* g1_heap_summary) const {
+ visit((GCHeapSummary*)g1_heap_summary);
+
+ EventG1HeapSummary e;
+ if (e.should_commit()) {
+ e.set_gcId(_gc_id.id());
+ e.set_when((u1)_when);
+ e.set_edenUsedSize(g1_heap_summary->edenUsed());
+ e.set_edenTotalSize(g1_heap_summary->edenCapacity());
+ e.set_survivorUsedSize(g1_heap_summary->survivorUsed());
+ e.commit();
+ }
+ }
+
void visit(const PSHeapSummary* ps_heap_summary) const {
visit((GCHeapSummary*)ps_heap_summary);
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -127,11 +127,11 @@
set_barrier_set(rem_set()->bs());
ReservedSpace young_rs = heap_rs.first_part(gen_policy()->young_gen_spec()->max_size(), false, false);
- _young_gen = gen_policy()->young_gen_spec()->init(young_rs, 0, rem_set());
+ _young_gen = gen_policy()->young_gen_spec()->init(young_rs, rem_set());
heap_rs = heap_rs.last_part(gen_policy()->young_gen_spec()->max_size());
ReservedSpace old_rs = heap_rs.first_part(gen_policy()->old_gen_spec()->max_size(), false, false);
- _old_gen = gen_policy()->old_gen_spec()->init(old_rs, 1, rem_set());
+ _old_gen = gen_policy()->old_gen_spec()->init(old_rs, rem_set());
clear_incremental_collection_failed();
#if INCLUDE_ALL_GCS
@@ -202,12 +202,8 @@
return _young_gen->used() + _old_gen->used();
}
-// Save the "used_region" for generations level and lower.
-void GenCollectedHeap::save_used_regions(int level) {
- assert(level == 0 || level == 1, "Illegal level parameter");
- if (level == 1) {
- _old_gen->save_used_region();
- }
+void GenCollectedHeap::save_used_regions() {
+ _old_gen->save_used_region();
_young_gen->save_used_region();
}
@@ -337,8 +333,16 @@
record_gen_tops_before_GC();
if (PrintGC && Verbose) {
- gclog_or_tty->print("level=%d invoke=%d size=" SIZE_FORMAT,
- gen->level(),
+ // I didn't want to change the logging when removing the level concept,
+ // but I guess this logging could say young/old or something instead of 0/1.
+ uint level;
+ if (heap()->is_young_gen(gen)) {
+ level = 0;
+ } else {
+ level = 1;
+ }
+ gclog_or_tty->print("level=%u invoke=%d size=" SIZE_FORMAT,
+ level,
gen->stat_record()->invocations,
size * HeapWordSize);
}
@@ -399,7 +403,7 @@
gen->stat_record()->accumulated_time.stop();
- update_gc_stats(gen->level(), full);
+ update_gc_stats(gen, full);
if (run_verification && VerifyAfterGC) {
HandleMark hm; // Discard invalid handles created during verification
@@ -412,11 +416,11 @@
}
}
-void GenCollectedHeap::do_collection(bool full,
- bool clear_all_soft_refs,
- size_t size,
- bool is_tlab,
- int max_level) {
+void GenCollectedHeap::do_collection(bool full,
+ bool clear_all_soft_refs,
+ size_t size,
+ bool is_tlab,
+ GenerationType max_generation) {
ResourceMark rm;
DEBUG_ONLY(Thread* my_thread = Thread::current();)
@@ -444,7 +448,7 @@
{
FlagSetting fl(_is_gc_active, true);
- bool complete = full && (max_level == 1 /* old */);
+ bool complete = full && (max_generation == OldGen);
const char* gc_cause_prefix = complete ? "Full GC" : "GC";
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
// The PrintGCDetails logging starts before we have incremented the GC id. We will do that later
@@ -458,9 +462,8 @@
bool run_verification = total_collections() >= VerifyGCStartAt;
bool prepared_for_verification = false;
- int max_level_collected = 0;
- bool old_collects_young = (max_level == 1) &&
- full &&
+ bool collected_old = false;
+ bool old_collects_young = complete &&
_old_gen->full_collects_younger_generations();
if (!old_collects_young &&
_young_gen->should_collect(full, size, is_tlab)) {
@@ -487,7 +490,7 @@
bool must_restore_marks_for_biased_locking = false;
- if (max_level == 1 && _old_gen->should_collect(full, size, is_tlab)) {
+ if (max_generation == OldGen && _old_gen->should_collect(full, size, is_tlab)) {
if (!complete) {
// The full_collections increment was missed above.
increment_total_full_collections();
@@ -510,13 +513,13 @@
true);
must_restore_marks_for_biased_locking = true;
- max_level_collected = 1;
+ collected_old = true;
}
// Update "complete" boolean wrt what actually transpired --
// for instance, a promotion failure could have led to
// a whole heap collection.
- complete = complete || (max_level_collected == 1 /* old */);
+ complete = complete || collected_old;
if (complete) { // We did a "major" collection
// FIXME: See comment at pre_full_gc_dump call
@@ -533,7 +536,7 @@
}
// Adjust generation sizes.
- if (max_level_collected == 1 /* old */) {
+ if (collected_old) {
_old_gen->compute_new_size();
}
_young_gen->compute_new_size();
@@ -661,11 +664,10 @@
DEBUG_ONLY(CodeBlobToOopClosure assert_code_is_non_scavengable(&assert_is_non_scavengable_closure, !CodeBlobToOopClosure::FixRelocations));
DEBUG_ONLY(CodeCache::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable));
}
-
}
void GenCollectedHeap::gen_process_roots(StrongRootsScope* scope,
- int level,
+ GenerationType type,
bool younger_gens_as_roots,
ScanningOption so,
bool only_strong_roots,
@@ -675,7 +677,7 @@
const bool is_adjust_phase = !only_strong_roots && !younger_gens_as_roots;
bool is_moving_collection = false;
- if (level == 0 || is_adjust_phase) {
+ if (type == YoungGen || is_adjust_phase) {
// young collections are always moving
is_moving_collection = true;
}
@@ -691,7 +693,7 @@
if (younger_gens_as_roots) {
if (!_process_strong_tasks->is_task_claimed(GCH_PS_younger_gens)) {
- if (level == 1) {
+ if (type == OldGen) {
not_older_gens->set_generation(_young_gen);
_young_gen->oop_iterate(not_older_gens);
}
@@ -699,8 +701,8 @@
}
}
// When collection is parallel, all threads get to cooperate to do
- // older-gen scanning.
- if (level == 0) {
+ // old generation scanning.
+ if (type == YoungGen) {
older_gens->set_generation(_old_gen);
rem_set()->younger_refs_iterate(_old_gen, older_gens, scope->n_threads());
older_gens->reset_generation();
@@ -724,10 +726,10 @@
#define GCH_SINCE_SAVE_MARKS_ITERATE_DEFN(OopClosureType, nv_suffix) \
void GenCollectedHeap:: \
-oop_since_save_marks_iterate(int level, \
+oop_since_save_marks_iterate(GenerationType gen, \
OopClosureType* cur, \
OopClosureType* older) { \
- if (level == 0) { \
+ if (gen == YoungGen) { \
_young_gen->oop_since_save_marks_iterate##nv_suffix(cur); \
_old_gen->oop_since_save_marks_iterate##nv_suffix(older); \
} else { \
@@ -739,8 +741,8 @@
#undef GCH_SINCE_SAVE_MARKS_ITERATE_DEFN
-bool GenCollectedHeap::no_allocs_since_save_marks(int level) {
- if (level == 0 && !_young_gen->no_allocs_since_save_marks()) {
+bool GenCollectedHeap::no_allocs_since_save_marks(bool include_young) {
+ if (include_young && !_young_gen->no_allocs_since_save_marks()) {
return false;
}
return _old_gen->no_allocs_since_save_marks();
@@ -770,47 +772,47 @@
#endif // INCLUDE_ALL_GCS
} else if (cause == GCCause::_wb_young_gc) {
// minor collection for WhiteBox API
- collect(cause, 0 /* young */);
+ collect(cause, YoungGen);
} else {
#ifdef ASSERT
if (cause == GCCause::_scavenge_alot) {
// minor collection only
- collect(cause, 0 /* young */);
+ collect(cause, YoungGen);
} else {
// Stop-the-world full collection
- collect(cause, 1 /* old */);
+ collect(cause, OldGen);
}
#else
// Stop-the-world full collection
- collect(cause, 1 /* old */);
+ collect(cause, OldGen);
#endif
}
}
-void GenCollectedHeap::collect(GCCause::Cause cause, int max_level) {
+void GenCollectedHeap::collect(GCCause::Cause cause, GenerationType max_generation) {
// The caller doesn't have the Heap_lock
assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock");
MutexLocker ml(Heap_lock);
- collect_locked(cause, max_level);
+ collect_locked(cause, max_generation);
}
void GenCollectedHeap::collect_locked(GCCause::Cause cause) {
// The caller has the Heap_lock
assert(Heap_lock->owned_by_self(), "this thread should own the Heap_lock");
- collect_locked(cause, 1 /* old */);
+ collect_locked(cause, OldGen);
}
// this is the private collection interface
// The Heap_lock is expected to be held on entry.
-void GenCollectedHeap::collect_locked(GCCause::Cause cause, int max_level) {
+void GenCollectedHeap::collect_locked(GCCause::Cause cause, GenerationType max_generation) {
// Read the GC count while holding the Heap_lock
unsigned int gc_count_before = total_collections();
unsigned int full_gc_count_before = total_full_collections();
{
MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back
VM_GenCollectFull op(gc_count_before, full_gc_count_before,
- cause, max_level);
+ cause, max_generation);
VMThread::execute(&op);
}
}
@@ -853,39 +855,39 @@
#endif // INCLUDE_ALL_GCS
void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs) {
- do_full_collection(clear_all_soft_refs, 1 /* old */);
+ do_full_collection(clear_all_soft_refs, OldGen);
}
void GenCollectedHeap::do_full_collection(bool clear_all_soft_refs,
- int max_level) {
- int local_max_level;
+ GenerationType last_generation) {
+ GenerationType local_last_generation;
if (!incremental_collection_will_fail(false /* don't consult_young */) &&
gc_cause() == GCCause::_gc_locker) {
- local_max_level = 0;
+ local_last_generation = YoungGen;
} else {
- local_max_level = max_level;
+ local_last_generation = last_generation;
}
- do_collection(true /* full */,
- clear_all_soft_refs /* clear_all_soft_refs */,
- 0 /* size */,
- false /* is_tlab */,
- local_max_level /* max_level */);
+ do_collection(true, // full
+ clear_all_soft_refs, // clear_all_soft_refs
+ 0, // size
+ false, // is_tlab
+ local_last_generation); // last_generation
// Hack XXX FIX ME !!!
// A scavenge may not have been attempted, or may have
// been attempted and failed, because the old gen was too full
- if (local_max_level == 0 && gc_cause() == GCCause::_gc_locker &&
+ if (local_last_generation == YoungGen && gc_cause() == GCCause::_gc_locker &&
incremental_collection_will_fail(false /* don't consult_young */)) {
if (PrintGCDetails) {
gclog_or_tty->print_cr("GC locker: Trying a full collection "
"because scavenge failed");
}
// This time allow the old gen to be collected as well
- do_collection(true /* full */,
- clear_all_soft_refs /* clear_all_soft_refs */,
- 0 /* size */,
- false /* is_tlab */,
- 1 /* old */ /* max_level */);
+ do_collection(true, // full
+ clear_all_soft_refs, // clear_all_soft_refs
+ 0, // size
+ false, // is_tlab
+ OldGen); // last_generation
}
}
@@ -1108,12 +1110,8 @@
_young_gen->prepare_for_compaction(&cp);
}
-GCStats* GenCollectedHeap::gc_stats(int level) const {
- if (level == 0) {
- return _young_gen->gc_stats();
- } else {
- return _old_gen->gc_stats();
- }
+GCStats* GenCollectedHeap::gc_stats(Generation* gen) const {
+ return gen->gc_stats();
}
void GenCollectedHeap::verify(bool silent, VerifyOption option /* ignored */) {
@@ -1283,7 +1281,7 @@
oop GenCollectedHeap::handle_failed_promotion(Generation* old_gen,
oop obj,
size_t obj_size) {
- guarantee(old_gen->level() == 1, "We only get here with an old generation");
+ guarantee(old_gen == _old_gen, "We only get here with an old generation");
assert(obj_size == (size_t)obj->size(), "bad obj_size passed in");
HeapWord* result = NULL;
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -55,6 +55,11 @@
public:
friend class VM_PopulateDumpSharedSpace;
+ enum GenerationType {
+ YoungGen,
+ OldGen
+ };
+
private:
Generation* _young_gen;
Generation* _old_gen;
@@ -95,11 +100,11 @@
// Helper function for two callbacks below.
// Considers collection of the first max_level+1 generations.
- void do_collection(bool full,
- bool clear_all_soft_refs,
- size_t size,
- bool is_tlab,
- int max_level);
+ void do_collection(bool full,
+ bool clear_all_soft_refs,
+ size_t size,
+ bool is_tlab,
+ GenerationType max_generation);
// Callback from VM_GenCollectForAllocation operation.
// This function does everything necessary/possible to satisfy an
@@ -110,7 +115,7 @@
// Callback from VM_GenCollectFull operation.
// Perform a full collection of the first max_level+1 generations.
virtual void do_full_collection(bool clear_all_soft_refs);
- void do_full_collection(bool clear_all_soft_refs, int max_level);
+ void do_full_collection(bool clear_all_soft_refs, GenerationType max_generation);
// Does the "cause" of GC indicate that
// we absolutely __must__ clear soft refs?
@@ -121,7 +126,7 @@
FlexibleWorkGang* workers() const { return _workers; }
- GCStats* gc_stats(int level) const;
+ GCStats* gc_stats(Generation* generation) const;
// Returns JNI_OK on success
virtual jint initialize();
@@ -142,6 +147,9 @@
Generation* young_gen() const { return _young_gen; }
Generation* old_gen() const { return _old_gen; }
+ bool is_young_gen(const Generation* gen) const { return gen == _young_gen; }
+ bool is_old_gen(const Generation* gen) const { return gen == _old_gen; }
+
// The generational collector policy.
GenCollectorPolicy* gen_policy() const { return _gen_policy; }
@@ -160,8 +168,8 @@
size_t capacity() const;
size_t used() const;
- // Save the "used_region" for generations level and lower.
- void save_used_regions(int level);
+ // Save the "used_region" for both generations.
+ void save_used_regions();
size_t max_capacity() const;
@@ -182,9 +190,9 @@
// The same as above but assume that the caller holds the Heap_lock.
void collect_locked(GCCause::Cause cause);
- // Perform a full collection of the first max_level+1 generations.
+ // Perform a full collection of generations up to and including max_generation.
// Mostly used for testing purposes. Caller does not hold the Heap_lock on entry.
- void collect(GCCause::Cause cause, int max_level);
+ void collect(GCCause::Cause cause, GenerationType max_generation);
// Returns "TRUE" iff "p" points into the committed areas of the heap.
// The methods is_in(), is_in_closed_subset() and is_in_youngest() may
@@ -314,10 +322,8 @@
}
// Update the gc statistics for each generation.
- // "level" is the level of the latest collection.
- void update_gc_stats(int current_level, bool full) {
- _young_gen->update_gc_stats(current_level, full);
- _old_gen->update_gc_stats(current_level, full);
+ void update_gc_stats(Generation* current_generation, bool full) {
+ _old_gen->update_gc_stats(current_generation, full);
}
bool no_gc_in_progress() { return !is_gc_active(); }
@@ -365,8 +371,8 @@
static GenCollectedHeap* heap();
// Invoke the "do_oop" method of one of the closures "not_older_gens"
- // or "older_gens" on root locations for the generation at
- // "level". (The "older_gens" closure is used for scanning references
+ // or "older_gens" on root locations for the generations depending on
+ // the type. (The "older_gens" closure is used for scanning references
// from older generations; "not_older_gens" is used everywhere else.)
// If "younger_gens_as_roots" is false, younger generations are
// not scanned as roots; in this case, the caller must be arranging to
@@ -396,7 +402,7 @@
static const bool StrongRootsOnly = true;
void gen_process_roots(StrongRootsScope* scope,
- int level,
+ GenerationType type,
bool younger_gens_as_roots,
ScanningOption so,
bool only_strong_roots,
@@ -420,7 +426,7 @@
// applied to references in the generation at "level", and the "older"
// closure to older generations.
#define GCH_SINCE_SAVE_MARKS_ITERATE_DECL(OopClosureType, nv_suffix) \
- void oop_since_save_marks_iterate(int level, \
+ void oop_since_save_marks_iterate(GenerationType start_gen, \
OopClosureType* cur, \
OopClosureType* older);
@@ -428,21 +434,17 @@
#undef GCH_SINCE_SAVE_MARKS_ITERATE_DECL
- // Returns "true" iff no allocations have occurred in any generation at
- // "level" or above since the last
+ // Returns "true" iff no allocations have occurred since the last
// call to "save_marks".
- bool no_allocs_since_save_marks(int level);
+ bool no_allocs_since_save_marks(bool include_young);
// Returns true if an incremental collection is likely to fail.
// We optionally consult the young gen, if asked to do so;
// otherwise we base our answer on whether the previous incremental
// collection attempt failed with no corrective action as of yet.
bool incremental_collection_will_fail(bool consult_young) {
- // Assumes a 2-generation system; the first disjunct remembers if an
- // incremental collection failed, even when we thought (second disjunct)
- // that it would not.
- assert(heap()->collector_policy()->is_generation_policy(),
- "the following definition may not be suitable for an n(>2)-generation system");
+ // The first disjunct remembers if an incremental collection failed, even
+ // when we thought (second disjunct) that it would not.
return incremental_collection_failed() ||
(consult_young && !_young_gen->collection_attempt_is_safe());
}
@@ -482,10 +484,10 @@
// iterating over spaces.
void prepare_for_compaction();
- // Perform a full collection of the first max_level+1 generations.
+ // Perform a full collection of the generations up to and including max_generation.
// This is the low level interface used by the public versions of
// collect() and collect_locked(). Caller holds the Heap_lock on entry.
- void collect_locked(GCCause::Cause cause, int max_level);
+ void collect_locked(GCCause::Cause cause, GenerationType max_generation);
// Returns success or failure.
bool create_cms_collector();
--- a/hotspot/src/share/vm/gc/shared/generation.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/generation.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -42,8 +42,7 @@
#include "utilities/copy.hpp"
#include "utilities/events.hpp"
-Generation::Generation(ReservedSpace rs, size_t initial_size, int level) :
- _level(level),
+Generation::Generation(ReservedSpace rs, size_t initial_size) :
_ref_processor(NULL) {
if (!_virtual_space.initialize(rs, initial_size)) {
vm_exit_during_initialization("Could not reserve enough space for "
@@ -61,8 +60,10 @@
GenerationSpec* Generation::spec() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
- assert(level() == 0 || level() == 1, "Bad gen level");
- return level() == 0 ? gch->gen_policy()->young_gen_spec() : gch->gen_policy()->old_gen_spec();
+ if (gch->is_young_gen(this)) {
+ return gch->gen_policy()->young_gen_spec();
+ }
+ return gch->gen_policy()->old_gen_spec();
}
size_t Generation::max_capacity() const {
@@ -111,9 +112,17 @@
void Generation::print_summary_info_on(outputStream* st) {
StatRecord* sr = stat_record();
double time = sr->accumulated_time.seconds();
+ // I didn't want to change the logging when removing the level concept,
+ // but I guess this logging could say young/old or something instead of 0/1.
+ uint level;
+ if (GenCollectedHeap::heap()->is_young_gen(this)) {
+ level = 0;
+ } else {
+ level = 1;
+ }
st->print_cr("[Accumulated GC generation %d time %3.7f secs, "
- "%d GC's, avg GC time %3.7f]",
- level(), time, sr->invocations,
+ "%u GC's, avg GC time %3.7f]",
+ level, time, sr->invocations,
sr->invocations > 0 ? time / sr->invocations : 0.0);
}
@@ -149,25 +158,14 @@
return blk.sp != NULL;
}
-Generation* Generation::next_gen() const {
- GenCollectedHeap* gch = GenCollectedHeap::heap();
- if (level() == 0) {
- return gch->old_gen();
- } else {
- return NULL;
- }
-}
-
size_t Generation::max_contiguous_available() const {
// The largest number of contiguous free words in this or any higher generation.
- size_t max = 0;
- for (const Generation* gen = this; gen != NULL; gen = gen->next_gen()) {
- size_t avail = gen->contiguous_available();
- if (avail > max) {
- max = avail;
- }
+ size_t avail = contiguous_available();
+ size_t old_avail = 0;
+ if (GenCollectedHeap::heap()->is_young_gen(this)) {
+ old_avail = GenCollectedHeap::heap()->old_gen()->contiguous_available();
}
- return max;
+ return MAX2(avail, old_avail);
}
bool Generation::promotion_attempt_is_safe(size_t max_promotion_in_bytes) const {
--- a/hotspot/src/share/vm/gc/shared/generation.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/generation.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -98,9 +98,6 @@
// Memory area reserved for generation
VirtualSpace _virtual_space;
- // Level in the generation hierarchy.
- int _level;
-
// ("Weak") Reference processing support
ReferenceProcessor* _ref_processor;
@@ -110,12 +107,8 @@
// Statistics for garbage collection
GCStats* _gc_stats;
- // Returns the next generation in the configuration, or else NULL if this
- // is the highest generation.
- Generation* next_gen() const;
-
// Initialize the generation.
- Generation(ReservedSpace rs, size_t initial_byte_size, int level);
+ Generation(ReservedSpace rs, size_t initial_byte_size);
// Apply "cl->do_oop" to (the address of) (exactly) all the ref fields in
// "sp" that point into younger generations.
@@ -409,15 +402,14 @@
_time_of_last_gc = now;
}
- // Generations may keep statistics about collection. This
- // method updates those statistics. current_level is
- // the level of the collection that has most recently
- // occurred. This allows the generation to decide what
- // statistics are valid to collect. For example, the
- // generation can decide to gather the amount of promoted data
- // if the collection of the younger generations has completed.
+ // Generations may keep statistics about collection. This method
+ // updates those statistics. current_generation is the generation
+ // that was most recently collected. This allows the generation to
+ // decide what statistics are valid to collect. For example, the
+ // generation can decide to gather the amount of promoted data if
+ // the collection of the younger generations has completed.
GCStats* gc_stats() const { return _gc_stats; }
- virtual void update_gc_stats(int current_level, bool full) {}
+ virtual void update_gc_stats(Generation* current_generation, bool full) {}
// Mark sweep support phase2
virtual void prepare_for_compaction(CompactPoint* cp);
@@ -502,8 +494,6 @@
virtual const char* name() const = 0;
virtual const char* short_name() const = 0;
- int level() const { return _level; }
-
// Reference Processing accessor
ReferenceProcessor* const ref_processor() { return _ref_processor; }
--- a/hotspot/src/share/vm/gc/shared/generationSpec.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/generationSpec.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -36,18 +36,17 @@
#include "gc/cms/parNewGeneration.hpp"
#endif // INCLUDE_ALL_GCS
-Generation* GenerationSpec::init(ReservedSpace rs, int level,
- GenRemSet* remset) {
+Generation* GenerationSpec::init(ReservedSpace rs, GenRemSet* remset) {
switch (name()) {
case Generation::DefNew:
- return new DefNewGeneration(rs, init_size(), level);
+ return new DefNewGeneration(rs, init_size());
case Generation::MarkSweepCompact:
- return new TenuredGeneration(rs, init_size(), level, remset);
+ return new TenuredGeneration(rs, init_size(), remset);
#if INCLUDE_ALL_GCS
case Generation::ParNew:
- return new ParNewGeneration(rs, init_size(), level);
+ return new ParNewGeneration(rs, init_size());
case Generation::ConcurrentMarkSweep: {
assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set");
@@ -61,7 +60,7 @@
ConcurrentMarkSweepGeneration* g = NULL;
g = new ConcurrentMarkSweepGeneration(rs,
- init_size(), level, ctrs, UseCMSAdaptiveFreeLists,
+ init_size(), ctrs, UseCMSAdaptiveFreeLists,
(FreeBlockDictionary<FreeChunk>::DictionaryChoice)CMSDictionaryChoice);
g->initialize_performance_counters();
--- a/hotspot/src/share/vm/gc/shared/generationSpec.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/generationSpec.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -45,7 +45,7 @@
_max_size(align_size_up(max_size, alignment))
{ }
- Generation* init(ReservedSpace rs, int level, GenRemSet* remset);
+ Generation* init(ReservedSpace rs, GenRemSet* remset);
// Accessors
Generation::Name name() const { return _name; }
--- a/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/vmGCOperations.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -184,7 +184,7 @@
GenCollectedHeap* gch = GenCollectedHeap::heap();
GCCauseSetter gccs(gch, _gc_cause);
- gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_level);
+ gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_generation);
}
// Returns true iff concurrent GCs unloads metadata.
@@ -197,7 +197,7 @@
if (UseG1GC && ClassUnloadingWithConcurrentMark) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
- g1h->g1_policy()->set_initiate_conc_mark_if_possible();
+ g1h->g1_policy()->collector_state()->set_initiate_conc_mark_if_possible(true);
GCCauseSetter x(g1h, _gc_cause);
--- a/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/gc/shared/vmGCOperations.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -26,6 +26,7 @@
#define SHARE_VM_GC_SHARED_VMGCOPERATIONS_HPP
#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/genCollectedHeap.hpp"
#include "memory/heapInspection.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/handles.hpp"
@@ -193,14 +194,14 @@
// GenCollectedHeap heap.
class VM_GenCollectFull: public VM_GC_Operation {
private:
- int _max_level;
+ GenCollectedHeap::GenerationType _max_generation;
public:
VM_GenCollectFull(uint gc_count_before,
uint full_gc_count_before,
GCCause::Cause gc_cause,
- int max_level)
+ GenCollectedHeap::GenerationType max_generation)
: VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true /* full */),
- _max_level(max_level) { }
+ _max_generation(max_generation) { }
~VM_GenCollectFull() {}
virtual VMOp_Type type() const { return VMOp_GenCollectFull; }
virtual void doit();
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -26,6 +26,7 @@
#include "classfile/javaClasses.inline.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/disassembler.hpp"
#include "gc/shared/collectedHeap.hpp"
@@ -309,6 +310,8 @@
Handle exception = get_preinitialized_exception(
SystemDictionary::StackOverflowError_klass(),
CHECK);
+ // Increment counter for hs_err file reporting
+ Atomic::inc(&Exceptions::_stack_overflow_errors);
THROW_HANDLE(exception);
IRT_END
@@ -1127,6 +1130,14 @@
// Implementation of SignatureHandlerLibrary
+#ifndef SHARING_FAST_NATIVE_FINGERPRINTS
+// Dummy definition (else normalization method is defined in CPU
+// dependant code)
+uint64_t InterpreterRuntime::normalize_fast_native_fingerprint(uint64_t fingerprint) {
+ return fingerprint;
+}
+#endif
+
address SignatureHandlerLibrary::set_handler_blob() {
BufferBlob* handler_blob = BufferBlob::create("native signature handlers", blob_size);
if (handler_blob == NULL) {
@@ -1182,6 +1193,8 @@
initialize();
// lookup method signature's fingerprint
uint64_t fingerprint = Fingerprinter(method).fingerprint();
+ // allow CPU dependant code to optimize the fingerprints for the fast handler
+ fingerprint = InterpreterRuntime::normalize_fast_native_fingerprint(fingerprint);
handler_index = _fingerprints->find(fingerprint);
// create handler if necessary
if (handler_index < 0) {
@@ -1207,13 +1220,18 @@
buffer.insts_size());
Disassembler::decode(handler, handler + buffer.insts_size());
#ifndef PRODUCT
- tty->print_cr(" --- associated result handler ---");
address rh_begin = Interpreter::result_handler(method()->result_type());
- address rh_end = rh_begin;
- while (*(int*)rh_end != 0) {
- rh_end += sizeof(int);
+ if (CodeCache::contains(rh_begin)) {
+ // else it might be special platform dependent values
+ tty->print_cr(" --- associated result handler ---");
+ address rh_end = rh_begin;
+ while (*(int*)rh_end != 0) {
+ rh_end += sizeof(int);
+ }
+ Disassembler::decode(rh_begin, rh_end);
+ } else {
+ tty->print_cr(" associated result handler: " PTR_FORMAT, p2i(rh_begin));
}
- Disassembler::decode(rh_begin, rh_end);
#endif
}
// add handler to library
@@ -1225,13 +1243,13 @@
}
}
// Set handler under SignatureHandlerLibrary_lock
- if (handler_index < 0) {
- // use generic signature handler
- method->set_signature_handler(Interpreter::slow_signature_handler());
- } else {
- // set handler
- method->set_signature_handler(_handlers->at(handler_index));
- }
+ if (handler_index < 0) {
+ // use generic signature handler
+ method->set_signature_handler(Interpreter::slow_signature_handler());
+ } else {
+ // set handler
+ method->set_signature_handler(_handlers->at(handler_index));
+ }
} else {
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
// use generic signature handler
@@ -1248,9 +1266,11 @@
// have to protect this read access here with the same mutex as well!
MutexLocker mu(SignatureHandlerLibrary_lock);
if (_handlers != NULL) {
- handler_index = _handlers->find(method->signature_handler());
- fingerprint_index = _fingerprints->find(Fingerprinter(method).fingerprint());
- }
+ handler_index = _handlers->find(method->signature_handler());
+ uint64_t fingerprint = Fingerprinter(method).fingerprint();
+ fingerprint = InterpreterRuntime::normalize_fast_native_fingerprint(fingerprint);
+ fingerprint_index = _fingerprints->find(fingerprint);
+ }
}
assert(method->signature_handler() == Interpreter::slow_signature_handler() ||
handler_index == fingerprint_index, "sanity check");
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -183,6 +183,8 @@
# include "interpreterRT_aarch64.hpp"
#endif
+ // optional normalization of fingerprints to reduce the number of adapters
+ static uint64_t normalize_fast_native_fingerprint(uint64_t fingerprint);
// Interpreter's frequency counter overflow
static nmethod* frequency_counter_overflow(JavaThread* thread, address branch_bcp);
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -102,7 +102,6 @@
static address _throw_ArrayStoreException_entry;
static address _throw_ArithmeticException_entry;
static address _throw_ClassCastException_entry;
- static address _throw_WrongMethodType_entry;
static address _throw_NullPointerException_entry;
static address _throw_exception_entry;
@@ -148,7 +147,6 @@
static address remove_activation_entry() { return _remove_activation_entry; }
static address throw_exception_entry() { return _throw_exception_entry; }
static address throw_ArithmeticException_entry() { return _throw_ArithmeticException_entry; }
- static address throw_WrongMethodType_entry() { return _throw_WrongMethodType_entry; }
static address throw_NullPointerException_entry() { return _throw_NullPointerException_entry; }
static address throw_StackOverflowError_entry() { return _throw_StackOverflowError_entry; }
--- a/hotspot/src/share/vm/memory/filemap.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/memory/filemap.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -28,10 +28,14 @@
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/altHashing.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1CollectedHeap.hpp"
+#endif
#include "memory/filemap.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/oopFactory.hpp"
#include "oops/objArrayOop.hpp"
+#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
#include "runtime/java.hpp"
#include "runtime/os.hpp"
@@ -165,6 +169,11 @@
_version = _current_version;
_alignment = alignment;
_obj_alignment = ObjectAlignmentInBytes;
+ _narrow_oop_mode = Universe::narrow_oop_mode();
+ _narrow_oop_shift = Universe::narrow_oop_shift();
+ _max_heap_size = MaxHeapSize;
+ _narrow_klass_base = Universe::narrow_klass_base();
+ _narrow_klass_shift = Universe::narrow_klass_shift();
_classpath_entry_table_size = mapinfo->_classpath_entry_table_size;
_classpath_entry_table = mapinfo->_classpath_entry_table;
_classpath_entry_size = mapinfo->_classpath_entry_size;
@@ -440,7 +449,16 @@
} else {
si->_file_offset = _file_offset;
}
- si->_base = base;
+ if (MetaspaceShared::is_string_region(region)) {
+ assert((base - (char*)Universe::narrow_oop_base()) % HeapWordSize == 0, "Sanity");
+ if (base != NULL) {
+ si->_addr._offset = (intx)oopDesc::encode_heap_oop_not_null((oop)base);
+ } else {
+ si->_addr._offset = 0;
+ }
+ } else {
+ si->_addr._base = base;
+ }
si->_used = size;
si->_capacity = capacity;
si->_read_only = read_only;
@@ -449,6 +467,38 @@
write_bytes_aligned(base, (int)size);
}
+// Write the string space. The string space contains one or multiple GC(G1) regions.
+// When the total string space size is smaller than one GC region of the dump time,
+// only one string region is used for shared strings.
+//
+// If the total string space size is bigger than one GC region, there would be more
+// than one GC regions allocated for shared strings. The first/bottom GC region might
+// be a partial GC region with the empty portion at the higher address within that region.
+// The non-empty portion of the first region is written into the archive as one string
+// region. The rest are consecutive full GC regions if they exist, which can be written
+// out in one chunk as another string region.
+void FileMapInfo::write_string_regions(GrowableArray<MemRegion> *regions) {
+ for (int i = MetaspaceShared::first_string;
+ i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
+ char* start = NULL;
+ size_t size = 0;
+ if (regions->is_nonempty()) {
+ if (i == MetaspaceShared::first_string) {
+ MemRegion first = regions->first();
+ start = (char*)first.start();
+ size = first.byte_size();
+ } else {
+ int len = regions->length();
+ if (len > 1) {
+ start = (char*)regions->at(1).start();
+ size = (char*)regions->at(len - 1).end() - start;
+ }
+ }
+ }
+ write_region(i, start, size, size, false, false);
+ }
+}
+
// Dump bytes to file -- at the current file position.
@@ -513,7 +563,8 @@
// JVM/TI RedefineClasses() support:
// Remap the shared readonly space to shared readwrite, private.
bool FileMapInfo::remap_shared_readonly_as_readwrite() {
- struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[0];
+ int idx = 0;
+ struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[idx];
if (!si->_read_only) {
// the space is already readwrite so we are done
return true;
@@ -523,15 +574,16 @@
if (!open_for_read()) {
return false;
}
+ char *addr = _header->region_addr(idx);
char *base = os::remap_memory(_fd, _full_path, si->_file_offset,
- si->_base, size, false /* !read_only */,
+ addr, size, false /* !read_only */,
si->_allow_exec);
close();
if (base == NULL) {
fail_continue("Unable to remap shared readonly space (errno=%d).", errno);
return false;
}
- if (base != si->_base) {
+ if (base != addr) {
fail_continue("Unable to remap shared readonly space at required address.");
return false;
}
@@ -542,7 +594,7 @@
// Map the whole region at once, assumed to be allocated contiguously.
ReservedSpace FileMapInfo::reserve_shared_memory() {
struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[0];
- char* requested_addr = si->_base;
+ char* requested_addr = _header->region_addr(0);
size_t size = FileMapInfo::shared_spaces_size();
@@ -560,20 +612,27 @@
}
// Memory map a region in the address space.
-static const char* shared_region_name[] = { "ReadOnly", "ReadWrite", "MiscData", "MiscCode"};
+static const char* shared_region_name[] = { "ReadOnly", "ReadWrite", "MiscData", "MiscCode",
+ "String1", "String2" };
char* FileMapInfo::map_region(int i) {
+ assert(!MetaspaceShared::is_string_region(i), "sanity");
struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
size_t used = si->_used;
size_t alignment = os::vm_allocation_granularity();
size_t size = align_size_up(used, alignment);
- char *requested_addr = si->_base;
+ char *requested_addr = _header->region_addr(i);
+
+ // If a tool agent is in use (debugging enabled), we must map the address space RW
+ if (JvmtiExport::can_modify_any_class() || JvmtiExport::can_walk_any_space()) {
+ si->_read_only = false;
+ }
// map the contents of the CDS archive in this memory
char *base = os::map_memory(_fd, _full_path, si->_file_offset,
requested_addr, size, si->_read_only,
si->_allow_exec);
- if (base == NULL || base != si->_base) {
+ if (base == NULL || base != requested_addr) {
fail_continue("Unable to map %s shared space at required address.", shared_region_name[i]);
return NULL;
}
@@ -582,15 +641,132 @@
// in method FileMapInfo::reserve_shared_memory(), which is not called on Windows.
MemTracker::record_virtual_memory_type((address)base, mtClassShared);
#endif
+
return base;
}
+static MemRegion *string_ranges = NULL;
+static int num_ranges = 0;
+bool FileMapInfo::map_string_regions() {
+#if INCLUDE_ALL_GCS
+ if (UseG1GC && UseCompressedOops && UseCompressedClassPointers) {
+ // Check that all the narrow oop and klass encodings match the archive
+ if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
+ narrow_oop_shift() != Universe::narrow_oop_shift() ||
+ narrow_klass_base() != Universe::narrow_klass_base() ||
+ narrow_klass_shift() != Universe::narrow_klass_shift()) {
+ if (PrintSharedSpaces && _header->_space[MetaspaceShared::first_string]._used > 0) {
+ tty->print_cr("Shared string data from the CDS archive is being ignored. "
+ "The current CompressedOops/CompressedClassPointers encoding differs from "
+ "that archived due to heap size change. The archive was dumped using max heap "
+ "size %dM.", max_heap_size()/M);
+ }
+ } else {
+ string_ranges = new MemRegion[MetaspaceShared::max_strings];
+ struct FileMapInfo::FileMapHeader::space_info* si;
+
+ for (int i = MetaspaceShared::first_string;
+ i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
+ si = &_header->_space[i];
+ size_t used = si->_used;
+ if (used > 0) {
+ size_t size = used;
+ char* requested_addr = (char*)((void*)oopDesc::decode_heap_oop_not_null(
+ (narrowOop)si->_addr._offset));
+ string_ranges[num_ranges] = MemRegion((HeapWord*)requested_addr, size / HeapWordSize);
+ num_ranges ++;
+ }
+ }
+
+ if (num_ranges == 0) {
+ StringTable::ignore_shared_strings(true);
+ return true; // no shared string data
+ }
+
+ // Check that ranges are within the java heap
+ if (!G1CollectedHeap::heap()->check_archive_addresses(string_ranges, num_ranges)) {
+ fail_continue("Unable to allocate shared string space: range is not "
+ "within java heap.");
+ return false;
+ }
+
+ // allocate from java heap
+ if (!G1CollectedHeap::heap()->alloc_archive_regions(string_ranges, num_ranges)) {
+ fail_continue("Unable to allocate shared string space: range is "
+ "already in use.");
+ return false;
+ }
+
+ // Map the string data. No need to call MemTracker::record_virtual_memory_type()
+ // for mapped string regions as they are part of the reserved java heap, which
+ // is already recorded.
+ for (int i = 0; i < num_ranges; i++) {
+ si = &_header->_space[MetaspaceShared::first_string + i];
+ char* addr = (char*)string_ranges[i].start();
+ char* base = os::map_memory(_fd, _full_path, si->_file_offset,
+ addr, string_ranges[i].byte_size(), si->_read_only,
+ si->_allow_exec);
+ if (base == NULL || base != addr) {
+ fail_continue("Unable to map shared string space at required address.");
+ return false;
+ }
+ }
+
+ if (!verify_string_regions()) {
+ fail_continue("Shared string regions are corrupt");
+ return false;
+ }
+
+ // the shared string data is mapped successfully
+ return true;
+ }
+ } else {
+ if (PrintSharedSpaces && _header->_space[MetaspaceShared::first_string]._used > 0) {
+ tty->print_cr("Shared string data from the CDS archive is being ignored. UseG1GC, "
+ "UseCompressedOops and UseCompressedClassPointers are required.");
+ }
+ }
+
+ // if we get here, the shared string data is not mapped
+ assert(string_ranges == NULL && num_ranges == 0, "sanity");
+ StringTable::ignore_shared_strings(true);
+#endif
+ return true;
+}
+
+bool FileMapInfo::verify_string_regions() {
+ for (int i = MetaspaceShared::first_string;
+ i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
+ if (!verify_region_checksum(i)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void FileMapInfo::fixup_string_regions() {
+ // If any string regions were found, call the fill routine to make them parseable.
+ // Note that string_ranges may be non-NULL even if no ranges were found.
+ if (num_ranges != 0) {
+ assert(string_ranges != NULL, "Null string_ranges array with non-zero count");
+ G1CollectedHeap::heap()->fill_archive_regions(string_ranges, num_ranges);
+ }
+}
+
bool FileMapInfo::verify_region_checksum(int i) {
if (!VerifySharedSpaces) {
return true;
}
- const char* buf = _header->_space[i]._base;
+
size_t sz = _header->_space[i]._used;
+
+ if (sz == 0) {
+ return true; // no data
+ }
+ if (MetaspaceShared::is_string_region(i) && StringTable::shared_string_ignored()) {
+ return true; // shared string data are not mapped
+ }
+ const char* buf = _header->region_addr(i);
int crc = ClassLoader::crc32(0, buf, (jint)sz);
if (crc != _header->_space[i]._crc) {
fail_continue("Checksum verification failed.");
@@ -602,14 +778,36 @@
// Unmap a memory region in the address space.
void FileMapInfo::unmap_region(int i) {
+ assert(!MetaspaceShared::is_string_region(i), "sanity");
struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
size_t used = si->_used;
size_t size = align_size_up(used, os::vm_allocation_granularity());
- if (!os::unmap_memory(si->_base, size)) {
+
+ if (used == 0) {
+ return;
+ }
+
+ char* addr = _header->region_addr(i);
+ if (!os::unmap_memory(addr, size)) {
fail_stop("Unable to unmap shared space.");
}
}
+void FileMapInfo::unmap_string_regions() {
+ for (int i = MetaspaceShared::first_string;
+ i < MetaspaceShared::first_string + MetaspaceShared::max_strings; i++) {
+ struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
+ size_t used = si->_used;
+ if (used > 0) {
+ size_t size = align_size_up(used, os::vm_allocation_granularity());
+ char* addr = (char*)((void*)oopDesc::decode_heap_oop_not_null(
+ (narrowOop)si->_addr._offset));
+ if (!os::unmap_memory(addr, size)) {
+ fail_stop("Unable to unmap shared space.");
+ }
+ }
+ }
+}
void FileMapInfo::assert_mark(bool check) {
if (!check) {
@@ -637,11 +835,6 @@
bool FileMapInfo::initialize() {
assert(UseSharedSpaces, "UseSharedSpaces expected.");
- if (JvmtiExport::can_modify_any_class() || JvmtiExport::can_walk_any_space()) {
- fail_continue("Tool agent requires sharing to be disabled.");
- return false;
- }
-
if (!open_for_read()) {
return false;
}
@@ -658,6 +851,15 @@
return true;
}
+char* FileMapInfo::FileMapHeader::region_addr(int idx) {
+ if (MetaspaceShared::is_string_region(idx)) {
+ return (char*)((void*)oopDesc::decode_heap_oop_not_null(
+ (narrowOop)_space[idx]._addr._offset));
+ } else {
+ return _space[idx]._addr._base;
+ }
+}
+
int FileMapInfo::FileMapHeader::compute_crc() {
char* header = data();
// start computing from the field after _crc
@@ -729,8 +931,12 @@
// True if the p is within the mapped shared space, otherwise, false.
bool FileMapInfo::is_in_shared_space(const void* p) {
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
- if (p >= _header->_space[i]._base &&
- p < _header->_space[i]._base + _header->_space[i]._used) {
+ char *base;
+ if (MetaspaceShared::is_string_region(i) && _header->_space[i]._used == 0) {
+ continue;
+ }
+ base = _header->region_addr(i);
+ if (p >= base && p < base + _header->_space[i]._used) {
return true;
}
}
@@ -742,9 +948,10 @@
gclog_or_tty->print_cr("Shared Spaces:");
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
struct FileMapInfo::FileMapHeader::space_info* si = &_header->_space[i];
+ char *base = _header->region_addr(i);
gclog_or_tty->print(" %s " INTPTR_FORMAT "-" INTPTR_FORMAT,
shared_region_name[i],
- si->_base, si->_base + si->_used);
+ base, base + si->_used);
}
}
@@ -753,12 +960,14 @@
FileMapInfo *map_info = FileMapInfo::current_info();
if (map_info) {
map_info->fail_continue("%s", msg);
- for (int i = 0; i < MetaspaceShared::n_regions; i++) {
- if (map_info->_header->_space[i]._base != NULL) {
+ for (int i = 0; i < MetaspaceShared::num_non_strings; i++) {
+ char *addr = map_info->_header->region_addr(i);
+ if (addr != NULL && !MetaspaceShared::is_string_region(i)) {
map_info->unmap_region(i);
- map_info->_header->_space[i]._base = NULL;
+ map_info->_header->_space[i]._addr._base = NULL;
}
}
+ map_info->unmap_string_regions();
} else if (DumpSharedSpaces) {
fail_stop("%s", msg);
}
--- a/hotspot/src/share/vm/memory/filemap.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/memory/filemap.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -94,11 +94,20 @@
int _version; // (from enum, above.)
size_t _alignment; // how shared archive should be aligned
int _obj_alignment; // value of ObjectAlignmentInBytes
+ int _narrow_oop_shift; // compressed oop encoding shift
+ uintx _max_heap_size; // java max heap size during dumping
+ Universe::NARROW_OOP_MODE _narrow_oop_mode; // compressed oop encoding mode
+ int _narrow_klass_shift; // save narrow klass base and shift
+ address _narrow_klass_base;
struct space_info {
int _crc; // crc checksum of the current space
size_t _file_offset; // sizeof(this) rounded to vm page size
- char* _base; // copy-on-write base address
+ union {
+ char* _base; // copy-on-write base address
+ intx _offset; // offset from the compressed oop encoding base, only used
+ // by string space
+ } _addr;
size_t _capacity; // for validity checking
size_t _used; // for setting space top on read
bool _read_only; // read only space?
@@ -138,6 +147,8 @@
size_t _classpath_entry_size;
SharedClassPathEntry* _classpath_entry_table;
+ char* region_addr(int idx);
+
virtual bool validate();
virtual void populate(FileMapInfo* info, size_t alignment);
int compute_crc();
@@ -166,8 +177,12 @@
void invalidate();
int version() { return _header->_version; }
size_t alignment() { return _header->_alignment; }
+ Universe::NARROW_OOP_MODE narrow_oop_mode() { return _header->_narrow_oop_mode; }
+ int narrow_oop_shift() { return _header->_narrow_oop_shift; }
+ uintx max_heap_size() { return _header->_max_heap_size; }
+ address narrow_klass_base() const { return _header->_narrow_klass_base; }
+ int narrow_klass_shift() const { return _header->_narrow_klass_shift; }
size_t space_capacity(int i) { return _header->_space[i]._capacity; }
- char* region_base(int i) { return _header->_space[i]._base; }
struct FileMapHeader* header() { return _header; }
static FileMapInfo* current_info() {
@@ -185,10 +200,15 @@
void write_space(int i, Metaspace* space, bool read_only);
void write_region(int region, char* base, size_t size,
size_t capacity, bool read_only, bool allow_exec);
+ void write_string_regions(GrowableArray<MemRegion> *regions);
void write_bytes(const void* buffer, int count);
void write_bytes_aligned(const void* buffer, int count);
char* map_region(int i);
+ bool map_string_regions();
+ bool verify_string_regions();
+ void fixup_string_regions();
void unmap_region(int i);
+ void unmap_string_regions();
bool verify_region_checksum(int i);
void close();
bool is_open() { return _file_open; }
--- a/hotspot/src/share/vm/memory/metaspace.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -2423,7 +2423,9 @@
* will be made to allocate a small chunk.
*/
MetaWord* SpaceManager::get_small_chunk_and_allocate(size_t word_size) {
- if (word_size + Metachunk::overhead() > small_chunk_size()) {
+ size_t raw_word_size = get_raw_word_size(word_size);
+
+ if (raw_word_size + Metachunk::overhead() > small_chunk_size()) {
return NULL;
}
@@ -2438,9 +2440,9 @@
// Add chunk to the in-use chunk list and do an allocation from it.
// Add to this manager's list of chunks in use.
add_chunk(chunk, false);
- mem = chunk->allocate(word_size);
-
- inc_used_metrics(word_size);
+ mem = chunk->allocate(raw_word_size);
+
+ inc_used_metrics(raw_word_size);
// Track metaspace memory usage statistic.
track_metaspace_memory_usage();
@@ -3132,10 +3134,21 @@
initialize_class_space(metaspace_rs);
if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) {
- gclog_or_tty->print_cr("Narrow klass base: " PTR_FORMAT ", Narrow klass shift: %d",
- p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
- gclog_or_tty->print_cr("Compressed class space size: " SIZE_FORMAT " Address: " PTR_FORMAT " Req Addr: " PTR_FORMAT,
- compressed_class_space_size(), p2i(metaspace_rs.base()), p2i(requested_addr));
+ print_compressed_class_space(gclog_or_tty, requested_addr);
+ }
+}
+
+void Metaspace::print_compressed_class_space(outputStream* st, const char* requested_addr) {
+ st->print_cr("Narrow klass base: " PTR_FORMAT ", Narrow klass shift: %d",
+ p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
+ if (_class_space_list != NULL) {
+ address base = (address)_class_space_list->current_virtual_space()->bottom();
+ st->print("Compressed class space size: " SIZE_FORMAT " Address: " PTR_FORMAT,
+ compressed_class_space_size(), p2i(base));
+ if (requested_addr != 0) {
+ st->print(" Req Addr: " PTR_FORMAT, p2i(requested_addr));
+ }
+ st->cr();
}
}
@@ -3282,12 +3295,12 @@
#endif // _LP64
#endif // INCLUDE_CDS
} else {
-#if INCLUDE_CDS
// If using shared space, open the file that contains the shared space
// and map in the memory before initializing the rest of metaspace (so
// the addresses don't conflict)
address cds_address = NULL;
if (UseSharedSpaces) {
+#if INCLUDE_CDS
FileMapInfo* mapinfo = new FileMapInfo();
// Open the shared archive file, read and validate the header. If
@@ -3296,27 +3309,30 @@
// Map in spaces now also
if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) {
cds_total = FileMapInfo::shared_spaces_size();
- cds_address = (address)mapinfo->region_base(0);
+ cds_address = (address)mapinfo->header()->region_addr(0);
+#ifdef _LP64
+ if (using_class_space()) {
+ char* cds_end = (char*)(cds_address + cds_total);
+ cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment);
+ // If UseCompressedClassPointers is set then allocate the metaspace area
+ // above the heap and above the CDS area (if it exists).
+ allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
+ // Map the shared string space after compressed pointers
+ // because it relies on compressed class pointers setting to work
+ mapinfo->map_string_regions();
+ }
+#endif // _LP64
} else {
assert(!mapinfo->is_open() && !UseSharedSpaces,
"archive file not closed or shared spaces not disabled.");
}
+#endif // INCLUDE_CDS
}
-#endif // INCLUDE_CDS
+
#ifdef _LP64
- // If UseCompressedClassPointers is set then allocate the metaspace area
- // above the heap and above the CDS area (if it exists).
- if (using_class_space()) {
- if (UseSharedSpaces) {
-#if INCLUDE_CDS
- char* cds_end = (char*)(cds_address + cds_total);
- cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment);
- allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
-#endif
- } else {
- char* base = (char*)align_ptr_up(Universe::heap()->reserved_region().end(), _reserve_alignment);
- allocate_metaspace_compressed_klass_ptrs(base, 0);
- }
+ if (!UseSharedSpaces && using_class_space()) {
+ char* base = (char*)align_ptr_up(Universe::heap()->reserved_region().end(), _reserve_alignment);
+ allocate_metaspace_compressed_klass_ptrs(base, 0);
}
#endif // _LP64
--- a/hotspot/src/share/vm/memory/metaspace.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/memory/metaspace.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -254,6 +254,8 @@
// Debugging support
void verify();
+ static void print_compressed_class_space(outputStream* st, const char* requested_addr = 0);
+
class AllocRecordClosure : public StackObj {
public:
virtual void doit(address ptr, MetaspaceObj::Type type, int byte_size) = 0;
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -422,6 +422,8 @@
GrowableArray<Klass*> *_class_promote_order;
VirtualSpace _md_vs;
VirtualSpace _mc_vs;
+ CompactHashtableWriter* _string_cht;
+ GrowableArray<MemRegion> *_string_regions;
public:
VM_PopulateDumpSharedSpace(ClassLoaderData* loader_data,
@@ -540,7 +542,7 @@
NOT_PRODUCT(SystemDictionary::verify();)
- // Copy the the symbol table, and the system dictionary to the shared
+ // Copy the the symbol table, string table, and the system dictionary to the shared
// space in usable form. Copy the hashtable
// buckets first [read-write], then copy the linked lists of entries
// [read-only].
@@ -548,6 +550,15 @@
NOT_PRODUCT(SymbolTable::verify());
handle_misc_data_space_failure(SymbolTable::copy_compact_table(&md_top, md_end));
+ size_t ss_bytes = 0;
+ char* ss_low;
+ // The string space has maximum two regions. See FileMapInfo::write_string_regions() for details.
+ _string_regions = new GrowableArray<MemRegion>(2);
+ NOT_PRODUCT(StringTable::verify());
+ handle_misc_data_space_failure(StringTable::copy_compact_table(&md_top, md_end, _string_regions,
+ &ss_bytes));
+ ss_low = _string_regions->is_empty() ? NULL : (char*)_string_regions->first().start();
+
SystemDictionary::reverse();
SystemDictionary::copy_buckets(&md_top, md_end);
@@ -576,7 +587,8 @@
const size_t rw_alloced = rw_space->capacity_bytes_slow(Metaspace::NonClassType);
const size_t md_alloced = md_end-md_low;
const size_t mc_alloced = mc_end-mc_low;
- const size_t total_alloced = ro_alloced + rw_alloced + md_alloced + mc_alloced;
+ const size_t total_alloced = ro_alloced + rw_alloced + md_alloced + mc_alloced
+ + ss_bytes;
// Occupied size of each space.
const size_t ro_bytes = ro_space->used_bytes_slow(Metaspace::NonClassType);
@@ -585,11 +597,12 @@
const size_t mc_bytes = size_t(mc_top - mc_low);
// Percent of total size
- const size_t total_bytes = ro_bytes + rw_bytes + md_bytes + mc_bytes;
+ const size_t total_bytes = ro_bytes + rw_bytes + md_bytes + mc_bytes + ss_bytes;
const double ro_t_perc = ro_bytes / double(total_bytes) * 100.0;
const double rw_t_perc = rw_bytes / double(total_bytes) * 100.0;
const double md_t_perc = md_bytes / double(total_bytes) * 100.0;
const double mc_t_perc = mc_bytes / double(total_bytes) * 100.0;
+ const double ss_t_perc = ss_bytes / double(total_bytes) * 100.0;
// Percent of fullness of each space
const double ro_u_perc = ro_bytes / double(ro_alloced) * 100.0;
@@ -602,6 +615,7 @@
tty->print_cr(fmt_space, "rw", rw_bytes, rw_t_perc, rw_alloced, rw_u_perc, rw_space->bottom());
tty->print_cr(fmt_space, "md", md_bytes, md_t_perc, md_alloced, md_u_perc, md_low);
tty->print_cr(fmt_space, "mc", mc_bytes, mc_t_perc, mc_alloced, mc_u_perc, mc_low);
+ tty->print_cr(fmt_space, "st", ss_bytes, ss_t_perc, ss_bytes, 100.0, ss_low);
tty->print_cr("total : %9d [100.0%% of total] out of %9d bytes [%4.1f%% used]",
total_bytes, total_alloced, total_u_perc);
@@ -631,6 +645,7 @@
pointer_delta(mc_top, _mc_vs.low(), sizeof(char)),
SharedMiscCodeSize,
true, true);
+ mapinfo->write_string_regions(_string_regions);
// Pass 2 - write data.
mapinfo->open_for_write();
@@ -646,6 +661,8 @@
pointer_delta(mc_top, _mc_vs.low(), sizeof(char)),
SharedMiscCodeSize,
true, true);
+ mapinfo->write_string_regions(_string_regions);
+
mapinfo->close();
memmove(vtbl_list, saved_vtbl, vtbl_list_size * sizeof(void*));
@@ -942,6 +959,11 @@
return UseSharedSpaces && FileMapInfo::current_info()->is_in_shared_space(p);
}
+bool MetaspaceShared::is_string_region(int idx) {
+ return (idx >= MetaspaceShared::first_string &&
+ idx < MetaspaceShared::first_string + MetaspaceShared::max_strings);
+}
+
void MetaspaceShared::print_shared_spaces() {
if (UseSharedSpaces) {
FileMapInfo::current_info()->print_shared_spaces();
@@ -972,13 +994,13 @@
// Map each shared region
if ((_ro_base = mapinfo->map_region(ro)) != NULL &&
- mapinfo->verify_region_checksum(ro) &&
+ mapinfo->verify_region_checksum(ro) &&
(_rw_base = mapinfo->map_region(rw)) != NULL &&
- mapinfo->verify_region_checksum(rw) &&
+ mapinfo->verify_region_checksum(rw) &&
(_md_base = mapinfo->map_region(md)) != NULL &&
- mapinfo->verify_region_checksum(md) &&
+ mapinfo->verify_region_checksum(md) &&
(_mc_base = mapinfo->map_region(mc)) != NULL &&
- mapinfo->verify_region_checksum(mc) &&
+ mapinfo->verify_region_checksum(mc) &&
(image_alignment == (size_t)max_alignment()) &&
mapinfo->validate_classpath_entry_table()) {
// Success (no need to do anything)
@@ -1011,7 +1033,7 @@
void MetaspaceShared::initialize_shared_spaces() {
FileMapInfo *mapinfo = FileMapInfo::current_info();
- char* buffer = mapinfo->region_base(md);
+ char* buffer = mapinfo->header()->region_addr(md);
// Skip over (reserve space for) a list of addresses of C++ vtables
// for Klass objects. They get filled in later.
@@ -1027,13 +1049,16 @@
buffer += sizeof(intptr_t);
buffer += vtable_size;
- // Create the shared symbol table using the bucket array at this spot in the
+ // Create the shared symbol table using the compact table at this spot in the
// misc data space. (Todo: move this to read-only space. Currently
// this is mapped copy-on-write but will never be written into).
buffer = (char*)SymbolTable::init_shared_table(buffer);
SymbolTable::create_table();
+ // Create the shared string table using the compact table
+ buffer = (char*)StringTable::init_shared_table(mapinfo, buffer);
+
// Create the shared dictionary using the bucket array at this spot in
// the misc data space. Since the shared dictionary table is never
// modified, this region (of mapped pages) will be (effectively, if
@@ -1100,6 +1125,11 @@
}
}
+void MetaspaceShared::fixup_shared_string_regions() {
+ FileMapInfo *mapinfo = FileMapInfo::current_info();
+ mapinfo->fixup_string_regions();
+}
+
// JVM/TI RedefineClasses() support:
bool MetaspaceShared::remap_shared_readonly_as_readwrite() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -53,6 +53,7 @@
memset(this, 0, sizeof(*this));
}
CompactHashtableStats symbol;
+ CompactHashtableStats string;
};
// Class Data Sharing Support
@@ -90,7 +91,10 @@
rw = 1, // read-write shared space in the heap
md = 2, // miscellaneous data for initializing tables, etc.
mc = 3, // miscellaneous code - vtable replacement.
- n_regions = 4
+ max_strings = 2, // max number of string regions in string space
+ num_non_strings = 4, // number of non-string regions
+ first_string = num_non_strings, // index of first string region
+ n_regions = max_strings + num_non_strings // total number of regions
};
// Accessor functions to save shared space created for metadata, which has
@@ -124,10 +128,13 @@
}
static bool map_shared_spaces(FileMapInfo* mapinfo) NOT_CDS_RETURN_(false);
static void initialize_shared_spaces() NOT_CDS_RETURN;
+ static void fixup_shared_string_regions() NOT_CDS_RETURN;
// Return true if given address is in the mapped shared space.
static bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false);
+ static bool is_string_region(int idx) NOT_CDS_RETURN_(false);
+
static void generate_vtable_methods(void** vtbl_list,
void** vtable,
char** md_top, char* md_end,
--- a/hotspot/src/share/vm/memory/universe.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/memory/universe.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -311,6 +311,7 @@
SystemDictionary::Cloneable_klass(), "u3");
assert(_the_array_interfaces_array->at(1) ==
SystemDictionary::Serializable_klass(), "u3");
+ MetaspaceShared::fixup_shared_string_regions();
} else {
// Set up shared interfaces array. (Do this before supers are set up.)
_the_array_interfaces_array->at_put(0, SystemDictionary::Cloneable_klass());
@@ -754,7 +755,7 @@
Universe::set_narrow_ptrs_base(Universe::narrow_oop_base());
if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) {
- Universe::print_compressed_oops_mode();
+ Universe::print_compressed_oops_mode(tty);
}
// Tell tests in which mode we run.
@@ -781,27 +782,24 @@
return JNI_OK;
}
-void Universe::print_compressed_oops_mode() {
- tty->cr();
- tty->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB",
+void Universe::print_compressed_oops_mode(outputStream* st) {
+ st->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB",
p2i(Universe::heap()->base()), Universe::heap()->reserved_region().byte_size()/M);
- tty->print(", Compressed Oops mode: %s", narrow_oop_mode_to_string(narrow_oop_mode()));
+ st->print(", Compressed Oops mode: %s", narrow_oop_mode_to_string(narrow_oop_mode()));
if (Universe::narrow_oop_base() != 0) {
- tty->print(": " PTR_FORMAT, p2i(Universe::narrow_oop_base()));
+ st->print(": " PTR_FORMAT, p2i(Universe::narrow_oop_base()));
}
if (Universe::narrow_oop_shift() != 0) {
- tty->print(", Oop shift amount: %d", Universe::narrow_oop_shift());
+ st->print(", Oop shift amount: %d", Universe::narrow_oop_shift());
}
if (!Universe::narrow_oop_use_implicit_null_checks()) {
- tty->print(", no protected page in front of the heap");
+ st->print(", no protected page in front of the heap");
}
-
- tty->cr();
- tty->cr();
+ st->cr();
}
ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) {
--- a/hotspot/src/share/vm/memory/universe.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/memory/universe.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -398,7 +398,7 @@
static void set_narrow_ptrs_base(address a) { _narrow_ptrs_base = a; }
static address narrow_ptrs_base() { return _narrow_ptrs_base; }
- static void print_compressed_oops_mode();
+ static void print_compressed_oops_mode(outputStream* st);
// this is set in vm_version on sparc (and then reset in universe afaict)
static void set_narrow_oop_shift(int shift) {
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -381,6 +381,9 @@
if (!constants()->is_shared()) {
MetadataFactory::free_metadata(loader_data, constants());
}
+ // Delete any cached resolution errors for the constant pool
+ SystemDictionary::delete_resolution_error(constants());
+
set_constants(NULL);
}
--- a/hotspot/src/share/vm/opto/c2_globals.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/opto/c2_globals.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,4 +25,12 @@
#include "precompiled.hpp"
#include "opto/c2_globals.hpp"
-C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_EXPERIMENTAL_FLAG, MATERIALIZE_NOTPRODUCT_FLAG)
+C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
+ MATERIALIZE_PD_DEVELOPER_FLAG, \
+ MATERIALIZE_PRODUCT_FLAG, \
+ MATERIALIZE_PD_PRODUCT_FLAG, \
+ MATERIALIZE_DIAGNOSTIC_FLAG, \
+ MATERIALIZE_EXPERIMENTAL_FLAG, \
+ MATERIALIZE_NOTPRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -61,7 +61,7 @@
// Defines all globals flags used by the server compiler.
//
-#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct) \
+#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, range, constraint) \
\
develop(bool, StressLCM, false, \
"Randomize instruction scheduling in LCM") \
@@ -94,7 +94,8 @@
"in generated code (in bytes)") \
\
product(intx, MaxLoopPad, (OptoLoopAlignment-1), \
- "Align a loop if padding size in bytes is less or equal to this value") \
+ "Align a loop if padding size in bytes is less or equal to this " \
+ "value") \
\
product(intx, MaxVectorSize, 64, \
"Max vector size in bytes, " \
@@ -108,6 +109,7 @@
\
notproduct(intx, IndexSetWatch, 0, \
"Trace all operations on this IndexSet (-1 means all, 0 none)") \
+ range(-1, 0) \
\
develop(intx, OptoNodeListSize, 4, \
"Starting allocation size of Node_List data structures") \
@@ -368,6 +370,7 @@
"System-wide value, 0=nothing is printed, 3=all details printed. "\
"Level of detail of printouts can be set on a per-method level " \
"as well by using CompileCommand=option.") \
+ range(0, 3) \
\
develop(intx, PrintIdealGraphPort, 4444, \
"Ideal graph printer to network port") \
@@ -389,13 +392,16 @@
"Insert memory barrier after arraycopy call") \
\
develop(bool, SubsumeLoads, true, \
- "Attempt to compile while subsuming loads into machine instructions.") \
+ "Attempt to compile while subsuming loads into machine " \
+ "instructions.") \
\
develop(bool, StressRecompilation, false, \
- "Recompile each compiled method without subsuming loads or escape analysis.") \
+ "Recompile each compiled method without subsuming loads " \
+ "or escape analysis.") \
\
develop(intx, ImplicitNullCheckThreshold, 3, \
- "Don't do implicit null checks if NPE's in a method exceeds limit") \
+ "Don't do implicit null checks if NPE's in a method exceeds " \
+ "limit") \
\
product(intx, LoopOptsCount, 43, \
"Set level of loop optimization for tier 1 compiles") \
@@ -541,15 +547,16 @@
"Use edge frequencies to drive block ordering") \
\
product(intx, BlockLayoutMinDiamondPercentage, 20, \
- "Miniumum %% of a successor (predecessor) for which block layout "\
- "a will allow a fork (join) in a single chain") \
+ "Miniumum %% of a successor (predecessor) for which block " \
+ "layout a will allow a fork (join) in a single chain") \
+ range(0, 100) \
\
product(bool, BlockLayoutRotateLoops, true, \
"Allow back branches to be fall throughs in the block layour") \
\
develop(bool, InlineReflectionGetCallerClass, true, \
- "inline sun.reflect.Reflection.getCallerClass(), known to be part "\
- "of base library DLL") \
+ "inline sun.reflect.Reflection.getCallerClass(), known to be " \
+ "part of base library DLL") \
\
develop(bool, InlineObjectCopy, true, \
"inline Object.clone and Arrays.copyOf[Range] intrinsics") \
@@ -611,6 +618,7 @@
\
product(intx, TypeProfileMajorReceiverPercent, 90, \
"% of major receiver type to all profiled receivers") \
+ range(0, 100) \
\
diagnostic(bool, PrintIntrinsics, false, \
"prints attempted and successful inlining of intrinsics") \
@@ -650,6 +658,8 @@
product(intx, AliasLevel, 3, \
"0 for no aliasing, 1 for oop/field/static/array split, " \
"2 for class split, 3 for unique instances") \
+ range(0, 3) \
+ constraint(AliasLevelConstraintFunc) \
\
develop(bool, VerifyAliases, false, \
"perform extra checks on the results of alias analysis") \
@@ -696,6 +706,14 @@
develop(bool, StressArrayCopyMacroNode, false, \
"Perform ArrayCopy load/store replacement during IGVN only")
-C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG)
+C2_FLAGS(DECLARE_DEVELOPER_FLAG, \
+ DECLARE_PD_DEVELOPER_FLAG, \
+ DECLARE_PRODUCT_FLAG, \
+ DECLARE_PD_PRODUCT_FLAG, \
+ DECLARE_DIAGNOSTIC_FLAG, \
+ DECLARE_EXPERIMENTAL_FLAG, \
+ DECLARE_NOTPRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
#endif // SHARE_VM_OPTO_C2_GLOBALS_HPP
--- a/hotspot/src/share/vm/opto/graphKit.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/opto/graphKit.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -3803,6 +3803,11 @@
Node* zero = __ ConI(0); // Dirty card value
BasicType bt = T_BYTE;
+ if (UseConcMarkSweepGC && UseCondCardMark) {
+ insert_mem_bar(Op_MemBarVolatile); // StoreLoad barrier
+ __ sync_kit(this);
+ }
+
if (UseCondCardMark) {
// The classic GC reference write barrier is typically implemented
// as a store into the global card mark table. Unfortunately
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -4089,9 +4089,6 @@
mnt->adjust_method_entries(the_class(), &trace_name_printed);
}
- // Fix Resolution Error table also to remove old constant pools
- SystemDictionary::delete_resolution_error(old_constants);
-
if (the_class->oop_map_cache() != NULL) {
// Flush references to any obsolete methods from the oop map cache
// so that obsolete methods are not pinned.
--- a/hotspot/src/share/vm/prims/whitebox.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -31,6 +31,7 @@
#include "code/codeCache.hpp"
#include "jvmtifiles/jvmtiEnv.hpp"
#include "memory/metadataFactory.hpp"
+#include "memory/metaspaceShared.hpp"
#include "memory/universe.hpp"
#include "oops/oop.inline.hpp"
#include "prims/wbtestmethods/parserTests.hpp"
@@ -89,6 +90,10 @@
return os::vm_page_size();
WB_END
+WB_ENTRY(jlong, WB_GetVMAllocationGranularity(JNIEnv* env, jobject o))
+ return os::vm_allocation_granularity();
+WB_END
+
WB_ENTRY(jlong, WB_GetVMLargePageSize(JNIEnv* env, jobject o))
return os::large_page_size();
WB_END
@@ -630,27 +635,27 @@
WB_END
template <typename T>
-static bool GetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, bool (*TAt)(const char*, T*, bool, bool)) {
+static bool GetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, Flag::Error (*TAt)(const char*, T*, bool, bool)) {
if (name == NULL) {
return false;
}
ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
const char* flag_name = env->GetStringUTFChars(name, NULL);
- bool result = (*TAt)(flag_name, value, true, true);
+ Flag::Error result = (*TAt)(flag_name, value, true, true);
env->ReleaseStringUTFChars(name, flag_name);
- return result;
+ return (result == Flag::SUCCESS);
}
template <typename T>
-static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, bool (*TAtPut)(const char*, T*, Flag::Flags)) {
+static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, Flag::Error (*TAtPut)(const char*, T*, Flag::Flags)) {
if (name == NULL) {
return false;
}
ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
const char* flag_name = env->GetStringUTFChars(name, NULL);
- bool result = (*TAtPut)(flag_name, value, Flag::INTERNAL);
+ Flag::Error result = (*TAtPut)(flag_name, value, Flag::INTERNAL);
env->ReleaseStringUTFChars(name, flag_name);
- return result;
+ return (result == Flag::SUCCESS);
}
template <typename T>
@@ -1207,6 +1212,15 @@
return NULL;
WB_END
+WB_ENTRY(jboolean, WB_IsShared(JNIEnv* env, jobject wb, jobject obj))
+ oop obj_oop = JNIHandles::resolve(obj);
+ return MetaspaceShared::is_in_shared_space((void*)obj_oop);
+WB_END
+
+WB_ENTRY(jboolean, WB_AreSharedStringsIgnored(JNIEnv* env))
+ return StringTable::shared_string_ignored();
+WB_END
+
//Some convenience methods to deal with objects from java
int WhiteBox::offset_for_field(const char* field_name, oop object,
Symbol* signature_symbol) {
@@ -1291,13 +1305,14 @@
#define CC (char*)
static JNINativeMethod methods[] = {
- {CC"getObjectAddress0", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress },
- {CC"getObjectSize0", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize },
- {CC"isObjectInOldGen0", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen },
- {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize },
- {CC"getVMPageSize", CC"()I", (void*)&WB_GetVMPageSize },
- {CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize},
- {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive },
+ {CC"getObjectAddress0", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress },
+ {CC"getObjectSize0", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize },
+ {CC"isObjectInOldGen0", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen },
+ {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize },
+ {CC"getVMPageSize", CC"()I", (void*)&WB_GetVMPageSize },
+ {CC"getVMAllocationGranularity", CC"()J", (void*)&WB_GetVMAllocationGranularity },
+ {CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize},
+ {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive },
{CC"parseCommandLine0",
CC"(Ljava/lang/String;C[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
(void*) &WB_ParseCommandLine
@@ -1431,6 +1446,8 @@
{CC"getMethodStringOption",
CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/String;",
(void*)&WB_GetMethodStringOption},
+ {CC"isShared", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsShared },
+ {CC"areSharedStringsIgnored", CC"()Z", (void*)&WB_AreSharedStringsIgnored },
};
#undef CC
--- a/hotspot/src/share/vm/runtime/arguments.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -38,6 +38,9 @@
#include "prims/jvmtiExport.hpp"
#include "runtime/arguments.hpp"
#include "runtime/arguments_ext.hpp"
+#include "runtime/commandLineFlagConstraintList.hpp"
+#include "runtime/commandLineFlagRangeList.hpp"
+#include "runtime/globals.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/java.hpp"
#include "runtime/os.hpp"
@@ -187,7 +190,6 @@
// Initialize system properties key and value.
void Arguments::init_system_properties() {
-
PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.name",
"Java Virtual Machine Specification", false));
PropertyList_add(&_system_properties, new SystemProperty("java.vm.version", VM_Version::vm_release(), false));
@@ -215,8 +217,7 @@
os::init_system_properties_values();
}
-
- // Update/Initialize System properties after JDK version number is known
+// Update/Initialize System properties after JDK version number is known
void Arguments::init_version_specific_system_properties() {
enum { bufsz = 16 };
char buffer[bufsz];
@@ -273,6 +274,7 @@
{ "UseCompilerSafepoints", JDK_Version::jdk(9), JDK_Version::jdk(10) },
{ "AdaptiveSizePausePolicy", JDK_Version::jdk(9), JDK_Version::jdk(10) },
{ "ParallelGCRetainPLAB", JDK_Version::jdk(9), JDK_Version::jdk(10) },
+ { "ThreadSafetyMargin", JDK_Version::jdk(9), JDK_Version::jdk(10) },
{ NULL, JDK_Version(0), JDK_Version(0) }
};
@@ -569,7 +571,11 @@
}
static bool set_bool_flag(char* name, bool value, Flag::Flags origin) {
- return CommandLineFlags::boolAtPut(name, &value, origin);
+ if (CommandLineFlags::boolAtPut(name, &value, origin) == Flag::SUCCESS) {
+ return true;
+ } else {
+ return false;
+ }
}
static bool set_fp_numeric_flag(char* name, char* value, Flag::Flags origin) {
@@ -578,7 +584,7 @@
return false;
}
- if (CommandLineFlags::doubleAtPut(name, &v, origin)) {
+ if (CommandLineFlags::doubleAtPut(name, &v, origin) == Flag::SUCCESS) {
return true;
}
return false;
@@ -591,7 +597,7 @@
bool is_neg = false;
// Check the sign first since atomull() parses only unsigned values.
if (*value == '-') {
- if (!CommandLineFlags::intxAt(name, &intx_v) && !CommandLineFlags::intAt(name, &int_v)) {
+ if ((CommandLineFlags::intxAt(name, &intx_v) != Flag::SUCCESS) && (CommandLineFlags::intAt(name, &int_v) != Flag::SUCCESS)) {
return false;
}
value++;
@@ -604,37 +610,37 @@
if (is_neg) {
int_v = -int_v;
}
- if (CommandLineFlags::intAtPut(name, &int_v, origin)) {
+ if (CommandLineFlags::intAtPut(name, &int_v, origin) == Flag::SUCCESS) {
return true;
}
uint uint_v = (uint) v;
- if (!is_neg && CommandLineFlags::uintAtPut(name, &uint_v, origin)) {
+ if (!is_neg && CommandLineFlags::uintAtPut(name, &uint_v, origin) == Flag::SUCCESS) {
return true;
}
intx_v = (intx) v;
if (is_neg) {
intx_v = -intx_v;
}
- if (CommandLineFlags::intxAtPut(name, &intx_v, origin)) {
+ if (CommandLineFlags::intxAtPut(name, &intx_v, origin) == Flag::SUCCESS) {
return true;
}
uintx uintx_v = (uintx) v;
- if (!is_neg && CommandLineFlags::uintxAtPut(name, &uintx_v, origin)) {
+ if (!is_neg && (CommandLineFlags::uintxAtPut(name, &uintx_v, origin) == Flag::SUCCESS)) {
return true;
}
uint64_t uint64_t_v = (uint64_t) v;
- if (!is_neg && CommandLineFlags::uint64_tAtPut(name, &uint64_t_v, origin)) {
+ if (!is_neg && (CommandLineFlags::uint64_tAtPut(name, &uint64_t_v, origin) == Flag::SUCCESS)) {
return true;
}
size_t size_t_v = (size_t) v;
- if (!is_neg && CommandLineFlags::size_tAtPut(name, &size_t_v, origin)) {
+ if (!is_neg && (CommandLineFlags::size_tAtPut(name, &size_t_v, origin) == Flag::SUCCESS)) {
return true;
}
return false;
}
static bool set_string_flag(char* name, const char* value, Flag::Flags origin) {
- if (!CommandLineFlags::ccstrAtPut(name, &value, origin)) return false;
+ if (CommandLineFlags::ccstrAtPut(name, &value, origin) != Flag::SUCCESS) return false;
// Contract: CommandLineFlags always returns a pointer that needs freeing.
FREE_C_HEAP_ARRAY(char, value);
return true;
@@ -642,7 +648,7 @@
static bool append_to_string_flag(char* name, const char* new_value, Flag::Flags origin) {
const char* old_value = "";
- if (!CommandLineFlags::ccstrAt(name, &old_value)) return false;
+ if (CommandLineFlags::ccstrAt(name, &old_value) != Flag::SUCCESS) return false;
size_t old_len = old_value != NULL ? strlen(old_value) : 0;
size_t new_len = strlen(new_value);
const char* value;
@@ -1384,10 +1390,16 @@
if (!FLAG_IS_DEFAULT(OldPLABSize) || !FLAG_IS_DEFAULT(OldPLABWeight)) {
CFLS_LAB::modify_initialization(OldPLABSize, OldPLABWeight);
}
+
+ if (!ClassUnloading) {
+ FLAG_SET_CMDLINE(bool, CMSClassUnloadingEnabled, false);
+ FLAG_SET_CMDLINE(bool, ExplicitGCInvokesConcurrentAndUnloadsClasses, false);
+ }
+
if (PrintGCDetails && Verbose) {
tty->print_cr("MarkStackSize: %uk MarkStackSizeMax: %uk",
(unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K));
- tty->print_cr("ConcGCThreads: %u", (uint) ConcGCThreads);
+ tty->print_cr("ConcGCThreads: %u", ConcGCThreads);
}
}
#endif // INCLUDE_ALL_GCS
@@ -1407,61 +1419,16 @@
// Oop encoding heap max
OopEncodingHeapMax = (uint64_t(max_juint) + 1) << LogMinObjAlignmentInBytes;
+ if (SurvivorAlignmentInBytes == 0) {
+ SurvivorAlignmentInBytes = ObjectAlignmentInBytes;
+ }
+
#if INCLUDE_ALL_GCS
// Set CMS global values
CompactibleFreeListSpace::set_cms_values();
#endif // INCLUDE_ALL_GCS
}
-bool verify_object_alignment() {
- // Object alignment.
- if (!is_power_of_2(ObjectAlignmentInBytes)) {
- jio_fprintf(defaultStream::error_stream(),
- "error: ObjectAlignmentInBytes=%d must be power of 2\n",
- (int)ObjectAlignmentInBytes);
- return false;
- }
- if ((int)ObjectAlignmentInBytes < BytesPerLong) {
- jio_fprintf(defaultStream::error_stream(),
- "error: ObjectAlignmentInBytes=%d must be greater or equal %d\n",
- (int)ObjectAlignmentInBytes, BytesPerLong);
- return false;
- }
- // It does not make sense to have big object alignment
- // since a space lost due to alignment will be greater
- // then a saved space from compressed oops.
- if ((int)ObjectAlignmentInBytes > 256) {
- jio_fprintf(defaultStream::error_stream(),
- "error: ObjectAlignmentInBytes=%d must not be greater than 256\n",
- (int)ObjectAlignmentInBytes);
- return false;
- }
- // In case page size is very small.
- if ((int)ObjectAlignmentInBytes >= os::vm_page_size()) {
- jio_fprintf(defaultStream::error_stream(),
- "error: ObjectAlignmentInBytes=%d must be less than page size %d\n",
- (int)ObjectAlignmentInBytes, os::vm_page_size());
- return false;
- }
- if(SurvivorAlignmentInBytes == 0) {
- SurvivorAlignmentInBytes = ObjectAlignmentInBytes;
- } else {
- if (!is_power_of_2(SurvivorAlignmentInBytes)) {
- jio_fprintf(defaultStream::error_stream(),
- "error: SurvivorAlignmentInBytes=%d must be power of 2\n",
- (int)SurvivorAlignmentInBytes);
- return false;
- }
- if (SurvivorAlignmentInBytes < ObjectAlignmentInBytes) {
- jio_fprintf(defaultStream::error_stream(),
- "error: SurvivorAlignmentInBytes=%d must be greater than ObjectAlignmentInBytes=%d \n",
- (int)SurvivorAlignmentInBytes, (int)ObjectAlignmentInBytes);
- return false;
- }
- }
- return true;
-}
-
size_t Arguments::max_heap_for_compressed_oops() {
// Avoid sign flip.
assert(OopEncodingHeapMax > (uint64_t)os::vm_page_size(), "Unusual page size");
@@ -1568,7 +1535,11 @@
if (should_auto_select_low_pause_collector()) {
FLAG_SET_ERGO(bool, UseConcMarkSweepGC, true);
} else {
+#if defined(JAVASE_EMBEDDED)
FLAG_SET_ERGO(bool, UseParallelGC, true);
+#else
+ FLAG_SET_ERGO(bool, UseG1GC, true);
+#endif
}
} else {
FLAG_SET_ERGO(bool, UseSerialGC, true);
@@ -1705,7 +1676,7 @@
if (PrintGCDetails && Verbose) {
tty->print_cr("MarkStackSize: %uk MarkStackSizeMax: %uk",
(unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K));
- tty->print_cr("ConcGCThreads: %u", (uint) ConcGCThreads);
+ tty->print_cr("ConcGCThreads: %u", ConcGCThreads);
}
}
@@ -1944,42 +1915,6 @@
//===========================================================================================================
// Parsing of main arguments
-bool Arguments::verify_interval(uintx val, uintx min,
- uintx max, const char* name) {
- // Returns true iff value is in the inclusive interval [min..max]
- // false, otherwise.
- if (val >= min && val <= max) {
- return true;
- }
- jio_fprintf(defaultStream::error_stream(),
- "%s of " UINTX_FORMAT " is invalid; must be between " UINTX_FORMAT
- " and " UINTX_FORMAT "\n",
- name, val, min, max);
- return false;
-}
-
-bool Arguments::verify_min_value(intx val, intx min, const char* name) {
- // Returns true if given value is at least specified min threshold
- // false, otherwise.
- if (val >= min ) {
- return true;
- }
- jio_fprintf(defaultStream::error_stream(),
- "%s of " INTX_FORMAT " is invalid; must be at least " INTX_FORMAT "\n",
- name, val, min);
- return false;
-}
-
-bool Arguments::verify_percentage(uintx value, const char* name) {
- if (is_percentage(value)) {
- return true;
- }
- jio_fprintf(defaultStream::error_stream(),
- "%s of " UINTX_FORMAT " is invalid; must be between 0 and 100\n",
- name, value);
- return false;
-}
-
// check if do gclog rotation
// +UseGCLogFileRotation is a must,
// no gc log rotation when log file not supplied or
@@ -1996,9 +1931,10 @@
}
if (UseGCLogFileRotation && (GCLogFileSize != 0) && (GCLogFileSize < 8*K)) {
- FLAG_SET_CMDLINE(size_t, GCLogFileSize, 8*K);
- jio_fprintf(defaultStream::output_stream(),
+ if (FLAG_SET_CMDLINE(size_t, GCLogFileSize, 8*K) == Flag::SUCCESS) {
+ jio_fprintf(defaultStream::output_stream(),
"GCLogFileSize changed to minimum 8K\n");
+ }
}
}
@@ -2047,38 +1983,6 @@
return count_p < 2 && count_t < 2;
}
-bool Arguments::verify_MinHeapFreeRatio(FormatBuffer<80>& err_msg, uintx min_heap_free_ratio) {
- if (!is_percentage(min_heap_free_ratio)) {
- err_msg.print("MinHeapFreeRatio must have a value between 0 and 100");
- return false;
- }
- if (min_heap_free_ratio > MaxHeapFreeRatio) {
- err_msg.print("MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or "
- "equal to MaxHeapFreeRatio (" UINTX_FORMAT ")", min_heap_free_ratio,
- MaxHeapFreeRatio);
- return false;
- }
- // This does not set the flag itself, but stores the value in a safe place for later usage.
- _min_heap_free_ratio = min_heap_free_ratio;
- return true;
-}
-
-bool Arguments::verify_MaxHeapFreeRatio(FormatBuffer<80>& err_msg, uintx max_heap_free_ratio) {
- if (!is_percentage(max_heap_free_ratio)) {
- err_msg.print("MaxHeapFreeRatio must have a value between 0 and 100");
- return false;
- }
- if (max_heap_free_ratio < MinHeapFreeRatio) {
- err_msg.print("MaxHeapFreeRatio (" UINTX_FORMAT ") must be greater than or "
- "equal to MinHeapFreeRatio (" UINTX_FORMAT ")", max_heap_free_ratio,
- MinHeapFreeRatio);
- return false;
- }
- // This does not set the flag itself, but stores the value in a safe place for later usage.
- _max_heap_free_ratio = max_heap_free_ratio;
- return true;
-}
-
// Check consistency of GC selection
bool Arguments::check_gc_consistency() {
check_gclog_consistency();
@@ -2126,17 +2030,6 @@
}
}
-// Check stack pages settings
-bool Arguments::check_stack_pages()
-{
- bool status = true;
- status = status && verify_min_value(StackYellowPages, 1, "StackYellowPages");
- status = status && verify_min_value(StackRedPages, 1, "StackRedPages");
- // greater stack shadow pages can't generate instruction to bang stack
- status = status && verify_interval(StackShadowPages, 1, 50, "StackShadowPages");
- return status;
-}
-
// Check the consistency of vm_init_args
bool Arguments::check_vm_args_consistency() {
// Method for adding checks for flag consistency.
@@ -2153,50 +2046,6 @@
status = false;
}
- status = status && verify_interval(AdaptiveSizePolicyWeight, 0, 100,
- "AdaptiveSizePolicyWeight");
- status = status && verify_percentage(ThresholdTolerance, "ThresholdTolerance");
-
- // Divide by bucket size to prevent a large size from causing rollover when
- // calculating amount of memory needed to be allocated for the String table.
- status = status && verify_interval(StringTableSize, minimumStringTableSize,
- (max_uintx / StringTable::bucket_size()), "StringTable size");
-
- status = status && verify_interval(SymbolTableSize, minimumSymbolTableSize,
- (max_uintx / SymbolTable::bucket_size()), "SymbolTable size");
-
- {
- // Using "else if" below to avoid printing two error messages if min > max.
- // This will also prevent us from reporting both min>100 and max>100 at the
- // same time, but that is less annoying than printing two identical errors IMHO.
- FormatBuffer<80> err_msg("%s","");
- if (!verify_MinHeapFreeRatio(err_msg, MinHeapFreeRatio)) {
- jio_fprintf(defaultStream::error_stream(), "%s\n", err_msg.buffer());
- status = false;
- } else if (!verify_MaxHeapFreeRatio(err_msg, MaxHeapFreeRatio)) {
- jio_fprintf(defaultStream::error_stream(), "%s\n", err_msg.buffer());
- status = false;
- }
- }
-
- // Min/MaxMetaspaceFreeRatio
- status = status && verify_percentage(MinMetaspaceFreeRatio, "MinMetaspaceFreeRatio");
- status = status && verify_percentage(MaxMetaspaceFreeRatio, "MaxMetaspaceFreeRatio");
-
- if (MinMetaspaceFreeRatio > MaxMetaspaceFreeRatio) {
- jio_fprintf(defaultStream::error_stream(),
- "MinMetaspaceFreeRatio (%s" UINTX_FORMAT ") must be less than or "
- "equal to MaxMetaspaceFreeRatio (%s" UINTX_FORMAT ")\n",
- FLAG_IS_DEFAULT(MinMetaspaceFreeRatio) ? "Default: " : "",
- MinMetaspaceFreeRatio,
- FLAG_IS_DEFAULT(MaxMetaspaceFreeRatio) ? "Default: " : "",
- MaxMetaspaceFreeRatio);
- status = false;
- }
-
- // Trying to keep 100% free is not practical
- MinMetaspaceFreeRatio = MIN2(MinMetaspaceFreeRatio, (uintx) 99);
-
if (FullGCALot && FLAG_IS_DEFAULT(MarkSweepAlwaysCompactCount)) {
MarkSweepAlwaysCompactCount = 1; // Move objects every gc.
}
@@ -2204,10 +2053,14 @@
if (UseParallelOldGC && ParallelOldGCSplitALot) {
// Settings to encourage splitting.
if (!FLAG_IS_CMDLINE(NewRatio)) {
- FLAG_SET_CMDLINE(uintx, NewRatio, 2);
+ if (FLAG_SET_CMDLINE(uintx, NewRatio, 2) != Flag::SUCCESS) {
+ status = false;
+ }
}
if (!FLAG_IS_CMDLINE(ScavengeBeforeFullGC)) {
- FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false);
+ if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != Flag::SUCCESS) {
+ status = false;
+ }
}
}
@@ -2215,18 +2068,12 @@
FLAG_SET_DEFAULT(ScavengeBeforeFullGC, false);
}
- status = status && verify_percentage(GCHeapFreeLimit, "GCHeapFreeLimit");
- status = status && verify_percentage(GCTimeLimit, "GCTimeLimit");
if (GCTimeLimit == 100) {
// Turn off gc-overhead-limit-exceeded checks
FLAG_SET_DEFAULT(UseGCOverheadLimit, false);
}
status = status && check_gc_consistency();
- status = status && check_stack_pages();
-
- status = status && verify_percentage(CMSIncrementalSafetyFactor,
- "CMSIncrementalSafetyFactor");
// CMS space iteration, which FLSVerifyAllHeapreferences entails,
// insists that we hold the requisite locks so that the iteration is
@@ -2260,132 +2107,6 @@
status = false;
}
- status = status && verify_min_value(ParGCArrayScanChunk, 1, "ParGCArrayScanChunk");
-
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- status = status && verify_percentage(G1NewSizePercent, "G1NewSizePercent");
- status = status && verify_percentage(G1MaxNewSizePercent, "G1MaxNewSizePercent");
- status = status && verify_interval(G1NewSizePercent, 0, G1MaxNewSizePercent, "G1NewSizePercent");
-
- status = status && verify_percentage(G1ConfidencePercent, "G1ConfidencePercent");
- status = status && verify_percentage(InitiatingHeapOccupancyPercent,
- "InitiatingHeapOccupancyPercent");
- status = status && verify_min_value(G1RefProcDrainInterval, 1,
- "G1RefProcDrainInterval");
- status = status && verify_min_value((intx)G1ConcMarkStepDurationMillis, 1,
- "G1ConcMarkStepDurationMillis");
- status = status && verify_interval(G1ConcRSHotCardLimit, 0, max_jubyte,
- "G1ConcRSHotCardLimit");
- status = status && verify_interval(G1ConcRSLogCacheSize, 0, 27,
- "G1ConcRSLogCacheSize");
- status = status && verify_interval(StringDeduplicationAgeThreshold, 1, markOopDesc::max_age,
- "StringDeduplicationAgeThreshold");
- }
- if (UseConcMarkSweepGC) {
- status = status && verify_min_value(CMSOldPLABNumRefills, 1, "CMSOldPLABNumRefills");
- status = status && verify_min_value(CMSOldPLABToleranceFactor, 1, "CMSOldPLABToleranceFactor");
- status = status && verify_min_value(CMSOldPLABMax, 1, "CMSOldPLABMax");
- status = status && verify_interval(CMSOldPLABMin, 1, CMSOldPLABMax, "CMSOldPLABMin");
-
- status = status && verify_min_value(CMSYoungGenPerWorker, 1, "CMSYoungGenPerWorker");
-
- status = status && verify_min_value(CMSSamplingGrain, 1, "CMSSamplingGrain");
- status = status && verify_interval(CMS_SweepWeight, 0, 100, "CMS_SweepWeight");
- status = status && verify_interval(CMS_FLSWeight, 0, 100, "CMS_FLSWeight");
-
- status = status && verify_interval(FLSCoalescePolicy, 0, 4, "FLSCoalescePolicy");
-
- status = status && verify_min_value(CMSRescanMultiple, 1, "CMSRescanMultiple");
- status = status && verify_min_value(CMSConcMarkMultiple, 1, "CMSConcMarkMultiple");
-
- status = status && verify_interval(CMSPrecleanIter, 0, 9, "CMSPrecleanIter");
- status = status && verify_min_value(CMSPrecleanDenominator, 1, "CMSPrecleanDenominator");
- status = status && verify_interval(CMSPrecleanNumerator, 0, CMSPrecleanDenominator - 1, "CMSPrecleanNumerator");
-
- status = status && verify_percentage(CMSBootstrapOccupancy, "CMSBootstrapOccupancy");
-
- status = status && verify_min_value(CMSPrecleanThreshold, 100, "CMSPrecleanThreshold");
-
- status = status && verify_percentage(CMSScheduleRemarkEdenPenetration, "CMSScheduleRemarkEdenPenetration");
- status = status && verify_min_value(CMSScheduleRemarkSamplingRatio, 1, "CMSScheduleRemarkSamplingRatio");
- status = status && verify_min_value(CMSBitMapYieldQuantum, 1, "CMSBitMapYieldQuantum");
- status = status && verify_percentage(CMSTriggerRatio, "CMSTriggerRatio");
- status = status && verify_percentage(CMSIsTooFullPercentage, "CMSIsTooFullPercentage");
- }
-
- if (UseParallelGC || UseParallelOldGC) {
- status = status && verify_interval(ParallelOldDeadWoodLimiterMean, 0, 100, "ParallelOldDeadWoodLimiterMean");
- status = status && verify_interval(ParallelOldDeadWoodLimiterStdDev, 0, 100, "ParallelOldDeadWoodLimiterStdDev");
-
- status = status && verify_percentage(YoungGenerationSizeIncrement, "YoungGenerationSizeIncrement");
- status = status && verify_percentage(TenuredGenerationSizeIncrement, "TenuredGenerationSizeIncrement");
-
- status = status && verify_min_value(YoungGenerationSizeSupplementDecay, 1, "YoungGenerationSizeSupplementDecay");
- status = status && verify_min_value(TenuredGenerationSizeSupplementDecay, 1, "TenuredGenerationSizeSupplementDecay");
-
- status = status && verify_min_value(ParGCCardsPerStrideChunk, 1, "ParGCCardsPerStrideChunk");
-
- status = status && verify_min_value(ParallelOldGCSplitInterval, 0, "ParallelOldGCSplitInterval");
- }
-#endif // INCLUDE_ALL_GCS
-
- status = status && verify_interval(RefDiscoveryPolicy,
- ReferenceProcessor::DiscoveryPolicyMin,
- ReferenceProcessor::DiscoveryPolicyMax,
- "RefDiscoveryPolicy");
-
- // Limit the lower bound of this flag to 1 as it is used in a division
- // expression.
- status = status && verify_interval(TLABWasteTargetPercent,
- 1, 100, "TLABWasteTargetPercent");
-
- status = status && verify_object_alignment();
-
- status = status && verify_interval(CompressedClassSpaceSize, 1*M, 3*G,
- "CompressedClassSpaceSize");
-
- status = status && verify_interval(MarkStackSizeMax,
- 1, (max_jint - 1), "MarkStackSizeMax");
- status = status && verify_interval(NUMAChunkResizeWeight, 0, 100, "NUMAChunkResizeWeight");
-
- status = status && verify_min_value(LogEventsBufferEntries, 1, "LogEventsBufferEntries");
-
- status = status && verify_min_value(HeapSizePerGCThread, (size_t) os::vm_page_size(), "HeapSizePerGCThread");
-
- status = status && verify_min_value(GCTaskTimeStampEntries, 1, "GCTaskTimeStampEntries");
-
- status = status && verify_percentage(ParallelGCBufferWastePct, "ParallelGCBufferWastePct");
- status = status && verify_interval(TargetPLABWastePct, 1, 100, "TargetPLABWastePct");
-
- status = status && verify_min_value(ParGCStridesPerThread, 1, "ParGCStridesPerThread");
-
- status = status && verify_min_value(MinRAMFraction, 1, "MinRAMFraction");
- status = status && verify_min_value(InitialRAMFraction, 1, "InitialRAMFraction");
- status = status && verify_min_value(MaxRAMFraction, 1, "MaxRAMFraction");
- status = status && verify_min_value(DefaultMaxRAMFraction, 1, "DefaultMaxRAMFraction");
-
- status = status && verify_interval(AdaptiveTimeWeight, 0, 100, "AdaptiveTimeWeight");
- status = status && verify_min_value(AdaptiveSizeDecrementScaleFactor, 1, "AdaptiveSizeDecrementScaleFactor");
-
- status = status && verify_interval(TLABAllocationWeight, 0, 100, "TLABAllocationWeight");
- status = status && verify_min_value(MinTLABSize, 1, "MinTLABSize");
- status = status && verify_min_value(TLABRefillWasteFraction, 1, "TLABRefillWasteFraction");
-
- status = status && verify_percentage(YoungGenerationSizeSupplement, "YoungGenerationSizeSupplement");
- status = status && verify_percentage(TenuredGenerationSizeSupplement, "TenuredGenerationSizeSupplement");
-
- status = status && verify_interval(MaxTenuringThreshold, 0, markOopDesc::max_age + 1, "MaxTenuringThreshold");
- status = status && verify_interval(InitialTenuringThreshold, 0, MaxTenuringThreshold, "InitialTenuringThreshold");
- status = status && verify_percentage(TargetSurvivorRatio, "TargetSurvivorRatio");
- status = status && verify_percentage(MarkSweepDeadRatio, "MarkSweepDeadRatio");
-
- status = status && verify_min_value(MarkSweepAlwaysCompactCount, 1, "MarkSweepAlwaysCompactCount");
-#ifdef COMPILER1
- status = status && verify_min_value(ValueMapInitialSize, 1, "ValueMapInitialSize");
-#endif
- status = status && verify_min_value(HeapSearchSteps, 1, "HeapSearchSteps");
-
if (PrintNMTStatistics) {
#if INCLUDE_NMT
if (MemTracker::tracking_level() == NMT_off) {
@@ -2397,26 +2118,6 @@
#endif
}
- // Need to limit the extent of the padding to reasonable size.
- // 8K is well beyond the reasonable HW cache line size, even with the
- // aggressive prefetching, while still leaving the room for segregating
- // among the distinct pages.
- if (ContendedPaddingWidth < 0 || ContendedPaddingWidth > 8192) {
- jio_fprintf(defaultStream::error_stream(),
- "ContendedPaddingWidth=" INTX_FORMAT " must be in between %d and %d\n",
- ContendedPaddingWidth, 0, 8192);
- status = false;
- }
-
- // Need to enforce the padding not to break the existing field alignments.
- // It is sufficient to check against the largest type size.
- if ((ContendedPaddingWidth % BytesPerLong) != 0) {
- jio_fprintf(defaultStream::error_stream(),
- "ContendedPaddingWidth=" INTX_FORMAT " must be a multiple of %d\n",
- ContendedPaddingWidth, BytesPerLong);
- status = false;
- }
-
// Check lower bounds of the code cache
// Template Interpreter code is approximately 3X larger in debug builds.
uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3);
@@ -2455,17 +2156,9 @@
status = false;
}
- status &= verify_interval(NmethodSweepActivity, 0, 2000, "NmethodSweepActivity");
- status &= verify_interval(CodeCacheMinBlockLength, 1, 100, "CodeCacheMinBlockLength");
- status &= verify_interval(CodeCacheSegmentSize, 1, 1024, "CodeCacheSegmentSize");
- status &= verify_interval(StartAggressiveSweepingAt, 0, 100, "StartAggressiveSweepingAt");
-
-
int min_number_of_compiler_threads = get_min_number_of_compiler_threads();
// The default CICompilerCount's value is CI_COMPILER_COUNT.
assert(min_number_of_compiler_threads <= CI_COMPILER_COUNT, "minimum should be less or equal default number");
- // Check the minimum number of compiler threads
- status &=verify_min_value(CICompilerCount, min_number_of_compiler_threads, "CICompilerCount");
if (!FLAG_IS_DEFAULT(CICompilerCount) && !FLAG_IS_DEFAULT(CICompilerCountPerCPU) && CICompilerCountPerCPU) {
warning("The VM option CICompilerCountPerCPU overrides CICompilerCount.");
@@ -2658,12 +2351,20 @@
// -verbose:[class/gc/jni]
if (match_option(option, "-verbose", &tail)) {
if (!strcmp(tail, ":class") || !strcmp(tail, "")) {
- FLAG_SET_CMDLINE(bool, TraceClassLoading, true);
- FLAG_SET_CMDLINE(bool, TraceClassUnloading, true);
+ if (FLAG_SET_CMDLINE(bool, TraceClassLoading, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, TraceClassUnloading, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (!strcmp(tail, ":gc")) {
- FLAG_SET_CMDLINE(bool, PrintGC, true);
+ if (FLAG_SET_CMDLINE(bool, PrintGC, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (!strcmp(tail, ":jni")) {
- FLAG_SET_CMDLINE(bool, PrintJNIResolving, true);
+ if (FLAG_SET_CMDLINE(bool, PrintJNIResolving, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
}
// -da / -ea / -disableassertions / -enableassertions
// These accept an optional class/package name separated by a colon, e.g.,
@@ -2750,16 +2451,24 @@
#endif // !INCLUDE_JVMTI
// -Xnoclassgc
} else if (match_option(option, "-Xnoclassgc")) {
- FLAG_SET_CMDLINE(bool, ClassUnloading, false);
+ if (FLAG_SET_CMDLINE(bool, ClassUnloading, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xconcgc
} else if (match_option(option, "-Xconcgc")) {
- FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true);
+ if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xnoconcgc
} else if (match_option(option, "-Xnoconcgc")) {
- FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false);
+ if (FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xbatch
} else if (match_option(option, "-Xbatch")) {
- FLAG_SET_CMDLINE(bool, BackgroundCompilation, false);
+ if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xmn for compatibility with other JVM vendors
} else if (match_option(option, "-Xmn", &tail)) {
julong long_initial_young_size = 0;
@@ -2770,8 +2479,12 @@
describe_range_error(errcode);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(size_t, MaxNewSize, (size_t)long_initial_young_size);
- FLAG_SET_CMDLINE(size_t, NewSize, (size_t)long_initial_young_size);
+ if (FLAG_SET_CMDLINE(size_t, MaxNewSize, (size_t)long_initial_young_size) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(size_t, NewSize, (size_t)long_initial_young_size) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xms
} else if (match_option(option, "-Xms", &tail)) {
julong long_initial_heap_size = 0;
@@ -2786,7 +2499,9 @@
set_min_heap_size((size_t)long_initial_heap_size);
// Currently the minimum size and the initial heap sizes are the same.
// Can be overridden with -XX:InitialHeapSize.
- FLAG_SET_CMDLINE(size_t, InitialHeapSize, (size_t)long_initial_heap_size);
+ if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, (size_t)long_initial_heap_size) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xmx
} else if (match_option(option, "-Xmx", &tail) || match_option(option, "-XX:MaxHeapSize=", &tail)) {
julong long_max_heap_size = 0;
@@ -2797,30 +2512,36 @@
describe_range_error(errcode);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(size_t, MaxHeapSize, (size_t)long_max_heap_size);
+ if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, (size_t)long_max_heap_size) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// Xmaxf
} else if (match_option(option, "-Xmaxf", &tail)) {
char* err;
int maxf = (int)(strtod(tail, &err) * 100);
- if (*err != '\0' || *tail == '\0' || maxf < 0 || maxf > 100) {
+ if (*err != '\0' || *tail == '\0') {
jio_fprintf(defaultStream::error_stream(),
"Bad max heap free percentage size: %s\n",
option->optionString);
return JNI_EINVAL;
} else {
- FLAG_SET_CMDLINE(uintx, MaxHeapFreeRatio, maxf);
+ if (FLAG_SET_CMDLINE(uintx, MaxHeapFreeRatio, maxf) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
}
// Xminf
} else if (match_option(option, "-Xminf", &tail)) {
char* err;
int minf = (int)(strtod(tail, &err) * 100);
- if (*err != '\0' || *tail == '\0' || minf < 0 || minf > 100) {
+ if (*err != '\0' || *tail == '\0') {
jio_fprintf(defaultStream::error_stream(),
"Bad min heap free percentage size: %s\n",
option->optionString);
return JNI_EINVAL;
} else {
- FLAG_SET_CMDLINE(uintx, MinHeapFreeRatio, minf);
+ if (FLAG_SET_CMDLINE(uintx, MinHeapFreeRatio, minf) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
}
// -Xss
} else if (match_option(option, "-Xss", &tail)) {
@@ -2833,8 +2554,10 @@
return JNI_EINVAL;
}
// Internally track ThreadStackSize in units of 1024 bytes.
- FLAG_SET_CMDLINE(intx, ThreadStackSize,
- round_to((int)long_ThreadStackSize, K) / K);
+ if (FLAG_SET_CMDLINE(intx, ThreadStackSize,
+ round_to((int)long_ThreadStackSize, K) / K) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xoss
} else if (match_option(option, "-Xoss", &tail)) {
// HotSpot does not have separate native and Java stacks, ignore silently for compatibility
@@ -2847,7 +2570,9 @@
os::vm_page_size()/K);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(uintx, CodeCacheExpansionSize, (uintx)long_CodeCacheExpansionSize);
+ if (FLAG_SET_CMDLINE(uintx, CodeCacheExpansionSize, (uintx)long_CodeCacheExpansionSize) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (match_option(option, "-Xmaxjitcodesize", &tail) ||
match_option(option, "-XX:ReservedCodeCacheSize=", &tail)) {
julong long_ReservedCodeCacheSize = 0;
@@ -2858,7 +2583,9 @@
"Invalid maximum code cache size: %s.\n", option->optionString);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize);
+ if (FLAG_SET_CMDLINE(uintx, ReservedCodeCacheSize, (uintx)long_ReservedCodeCacheSize) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -XX:NonNMethodCodeHeapSize=
} else if (match_option(option, "-XX:NonNMethodCodeHeapSize=", &tail)) {
julong long_NonNMethodCodeHeapSize = 0;
@@ -2869,7 +2596,9 @@
"Invalid maximum non-nmethod code heap size: %s.\n", option->optionString);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(uintx, NonNMethodCodeHeapSize, (uintx)long_NonNMethodCodeHeapSize);
+ if (FLAG_SET_CMDLINE(uintx, NonNMethodCodeHeapSize, (uintx)long_NonNMethodCodeHeapSize) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -XX:ProfiledCodeHeapSize=
} else if (match_option(option, "-XX:ProfiledCodeHeapSize=", &tail)) {
julong long_ProfiledCodeHeapSize = 0;
@@ -2880,7 +2609,9 @@
"Invalid maximum profiled code heap size: %s.\n", option->optionString);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(uintx, ProfiledCodeHeapSize, (uintx)long_ProfiledCodeHeapSize);
+ if (FLAG_SET_CMDLINE(uintx, ProfiledCodeHeapSize, (uintx)long_ProfiledCodeHeapSize) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -XX:NonProfiledCodeHeapSizee=
} else if (match_option(option, "-XX:NonProfiledCodeHeapSize=", &tail)) {
julong long_NonProfiledCodeHeapSize = 0;
@@ -2891,17 +2622,9 @@
"Invalid maximum non-profiled code heap size: %s.\n", option->optionString);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(uintx, NonProfiledCodeHeapSize, (uintx)long_NonProfiledCodeHeapSize);
- //-XX:IncreaseFirstTierCompileThresholdAt=
- } else if (match_option(option, "-XX:IncreaseFirstTierCompileThresholdAt=", &tail)) {
- uintx uint_IncreaseFirstTierCompileThresholdAt = 0;
- if (!parse_uintx(tail, &uint_IncreaseFirstTierCompileThresholdAt, 0) || uint_IncreaseFirstTierCompileThresholdAt > 99) {
- jio_fprintf(defaultStream::error_stream(),
- "Invalid value for IncreaseFirstTierCompileThresholdAt: %s. Should be between 0 and 99.\n",
- option->optionString);
- return JNI_EINVAL;
- }
- FLAG_SET_CMDLINE(uintx, IncreaseFirstTierCompileThresholdAt, (uintx)uint_IncreaseFirstTierCompileThresholdAt);
+ if (FLAG_SET_CMDLINE(uintx, NonProfiledCodeHeapSize, (uintx)long_NonProfiledCodeHeapSize) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -green
} else if (match_option(option, "-green")) {
jio_fprintf(defaultStream::error_stream(),
@@ -2916,10 +2639,14 @@
// -Xrs
} else if (match_option(option, "-Xrs")) {
// Classic/EVM option, new functionality
- FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true);
+ if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (match_option(option, "-Xusealtsigs")) {
// change default internal VM signals used - lower case for back compat
- FLAG_SET_CMDLINE(bool, UseAltSigs, true);
+ if (FLAG_SET_CMDLINE(bool, UseAltSigs, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xoptimize
} else if (match_option(option, "-Xoptimize")) {
// EVM option, ignore silently for compatibility
@@ -2934,11 +2661,21 @@
#endif // INCLUDE_FPROF
// -Xconcurrentio
} else if (match_option(option, "-Xconcurrentio")) {
- FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true);
- FLAG_SET_CMDLINE(bool, BackgroundCompilation, false);
- FLAG_SET_CMDLINE(intx, DeferThrSuspendLoopCount, 1);
- FLAG_SET_CMDLINE(bool, UseTLAB, false);
- FLAG_SET_CMDLINE(size_t, NewSizeThreadIncrease, 16 * K); // 20Kb per thread added to new generation
+ if (FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, BackgroundCompilation, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(intx, DeferThrSuspendLoopCount, 1) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, UseTLAB, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(size_t, NewSizeThreadIncrease, 16 * K) != Flag::SUCCESS) { // 20Kb per thread added to new generation
+ return JNI_EINVAL;
+ }
// -Xinternalversion
} else if (match_option(option, "-Xinternalversion")) {
@@ -2976,7 +2713,9 @@
// Out of the box management support
if (match_option(option, "-Dcom.sun.management", &tail)) {
#if INCLUDE_MANAGEMENT
- FLAG_SET_CMDLINE(bool, ManagementServer, true);
+ if (FLAG_SET_CMDLINE(bool, ManagementServer, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
#else
jio_fprintf(defaultStream::output_stream(),
"-Dcom.sun.management is not supported in this VM.\n");
@@ -2995,31 +2734,57 @@
set_mode_flags(_comp);
// -Xshare:dump
} else if (match_option(option, "-Xshare:dump")) {
- FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true);
+ if (FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
set_mode_flags(_int); // Prevent compilation, which creates objects
// -Xshare:on
} else if (match_option(option, "-Xshare:on")) {
- FLAG_SET_CMDLINE(bool, UseSharedSpaces, true);
- FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true);
+ if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xshare:auto
} else if (match_option(option, "-Xshare:auto")) {
- FLAG_SET_CMDLINE(bool, UseSharedSpaces, true);
- FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false);
+ if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xshare:off
} else if (match_option(option, "-Xshare:off")) {
- FLAG_SET_CMDLINE(bool, UseSharedSpaces, false);
- FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false);
+ if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// -Xverify
} else if (match_option(option, "-Xverify", &tail)) {
if (strcmp(tail, ":all") == 0 || strcmp(tail, "") == 0) {
- FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, true);
- FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true);
+ if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (strcmp(tail, ":remote") == 0) {
- FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false);
- FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true);
+ if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (strcmp(tail, ":none") == 0) {
- FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false);
- FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, false);
+ if (FLAG_SET_CMDLINE(bool, BytecodeVerificationLocal, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, BytecodeVerificationRemote, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (is_bad_option(option, args->ignoreUnrecognized, "verification")) {
return JNI_EINVAL;
}
@@ -3044,9 +2809,12 @@
"Note %%p or %%t can only be used once\n", _gc_log_filename);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(bool, PrintGC, true);
- FLAG_SET_CMDLINE(bool, PrintGCTimeStamps, true);
-
+ if (FLAG_SET_CMDLINE(bool, PrintGC, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, PrintGCTimeStamps, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// JNI hooks
} else if (match_option(option, "-Xcheck", &tail)) {
if (!strcmp(tail, ":jni")) {
@@ -3098,16 +2866,24 @@
initHeapSize = limit_by_allocatable_memory(initHeapSize);
if (FLAG_IS_DEFAULT(MaxHeapSize)) {
- FLAG_SET_CMDLINE(size_t, MaxHeapSize, initHeapSize);
- FLAG_SET_CMDLINE(size_t, InitialHeapSize, initHeapSize);
+ if (FLAG_SET_CMDLINE(size_t, MaxHeapSize, initHeapSize) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(size_t, InitialHeapSize, initHeapSize) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// Currently the minimum size and the initial heap sizes are the same.
set_min_heap_size(initHeapSize);
}
if (FLAG_IS_DEFAULT(NewSize)) {
// Make the young generation 3/8ths of the total heap.
- FLAG_SET_CMDLINE(size_t, NewSize,
- ((julong)MaxHeapSize / (julong)8) * (julong)3);
- FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize);
+ if (FLAG_SET_CMDLINE(size_t, NewSize,
+ ((julong)MaxHeapSize / (julong)8) * (julong)3) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(size_t, MaxNewSize, NewSize) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
}
#if !defined(_ALLBSD_SOURCE) && !defined(AIX) // UseLargePages is not yet supported on BSD and AIX.
@@ -3115,14 +2891,22 @@
#endif
// Increase some data structure sizes for efficiency
- FLAG_SET_CMDLINE(size_t, BaseFootPrintEstimate, MaxHeapSize);
- FLAG_SET_CMDLINE(bool, ResizeTLAB, false);
- FLAG_SET_CMDLINE(size_t, TLABSize, 256*K);
+ if (FLAG_SET_CMDLINE(size_t, BaseFootPrintEstimate, MaxHeapSize) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, ResizeTLAB, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(size_t, TLABSize, 256*K) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// See the OldPLABSize comment below, but replace 'after promotion'
// with 'after copying'. YoungPLABSize is the size of the survivor
// space per-gc-thread buffers. The default is 4kw.
- FLAG_SET_CMDLINE(size_t, YoungPLABSize, 256*K); // Note: this is in words
+ if (FLAG_SET_CMDLINE(size_t, YoungPLABSize, 256*K) != Flag::SUCCESS) { // Note: this is in words
+ return JNI_EINVAL;
+ }
// OldPLABSize is the size of the buffers in the old gen that
// UseParallelGC uses to promote live data that doesn't fit in the
@@ -3137,62 +2921,111 @@
// locality. A minor effect may be that larger PLABs reduce the
// number of PLAB allocation events during gc. The value of 8kw
// was arrived at by experimenting with specjbb.
- FLAG_SET_CMDLINE(size_t, OldPLABSize, 8*K); // Note: this is in words
+ if (FLAG_SET_CMDLINE(size_t, OldPLABSize, 8*K) != Flag::SUCCESS) { // Note: this is in words
+ return JNI_EINVAL;
+ }
// Enable parallel GC and adaptive generation sizing
- FLAG_SET_CMDLINE(bool, UseParallelGC, true);
+ if (FLAG_SET_CMDLINE(bool, UseParallelGC, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
FLAG_SET_DEFAULT(ParallelGCThreads,
Abstract_VM_Version::parallel_worker_threads());
// Encourage steady state memory management
- FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100);
+ if (FLAG_SET_CMDLINE(uintx, ThresholdTolerance, 100) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// This appears to improve mutator locality
- FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false);
+ if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// Get around early Solaris scheduling bug
// (affinity vs other jobs on system)
// but disallow DR and offlining (5008695).
- FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true);
+ if (FLAG_SET_CMDLINE(bool, BindGCTaskThreadsToCPUs, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// Need to keep consistency of MaxTenuringThreshold and AlwaysTenure/NeverTenure;
// and the last option wins.
} else if (match_option(option, "-XX:+NeverTenure")) {
- FLAG_SET_CMDLINE(bool, NeverTenure, true);
- FLAG_SET_CMDLINE(bool, AlwaysTenure, false);
- FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1);
+ if (FLAG_SET_CMDLINE(bool, NeverTenure, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, markOopDesc::max_age + 1) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (match_option(option, "-XX:+AlwaysTenure")) {
- FLAG_SET_CMDLINE(bool, NeverTenure, false);
- FLAG_SET_CMDLINE(bool, AlwaysTenure, true);
- FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0);
+ if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (match_option(option, "-XX:MaxTenuringThreshold=", &tail)) {
uintx max_tenuring_thresh = 0;
- if(!parse_uintx(tail, &max_tenuring_thresh, 0)) {
+ if (!parse_uintx(tail, &max_tenuring_thresh, 0)) {
jio_fprintf(defaultStream::error_stream(),
- "Improperly specified VM option 'MaxTenuringThreshold=%s'\n", tail);
+ "Improperly specified VM option \'MaxTenuringThreshold=%s\'\n", tail);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh);
+
+ if (FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, max_tenuring_thresh) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
if (MaxTenuringThreshold == 0) {
- FLAG_SET_CMDLINE(bool, NeverTenure, false);
- FLAG_SET_CMDLINE(bool, AlwaysTenure, true);
+ if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, AlwaysTenure, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else {
- FLAG_SET_CMDLINE(bool, NeverTenure, false);
- FLAG_SET_CMDLINE(bool, AlwaysTenure, false);
+ if (FLAG_SET_CMDLINE(bool, NeverTenure, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, AlwaysTenure, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
}
} else if (match_option(option, "-XX:+DisplayVMOutputToStderr")) {
- FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false);
- FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true);
+ if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (match_option(option, "-XX:+DisplayVMOutputToStdout")) {
- FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false);
- FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true);
+ if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (match_option(option, "-XX:+ExtendedDTraceProbes")) {
#if defined(DTRACE_ENABLED)
- FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true);
- FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true);
- FLAG_SET_CMDLINE(bool, DTraceAllocProbes, true);
- FLAG_SET_CMDLINE(bool, DTraceMonitorProbes, true);
+ if (FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, DTraceAllocProbes, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, DTraceMonitorProbes, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
#else // defined(DTRACE_ENABLED)
jio_fprintf(defaultStream::error_stream(),
"ExtendedDTraceProbes flag is not applicable for this configuration\n");
@@ -3200,9 +3033,13 @@
#endif // defined(DTRACE_ENABLED)
#ifdef ASSERT
} else if (match_option(option, "-XX:+FullGCALot")) {
- FLAG_SET_CMDLINE(bool, FullGCALot, true);
+ if (FLAG_SET_CMDLINE(bool, FullGCALot, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
// disable scavenge before parallel mark-compact
- FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false);
+ if (FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
#endif
} else if (match_option(option, "-XX:CMSMarkStackSize=", &tail) ||
match_option(option, "-XX:G1MarkStackSize=", &tail)) {
@@ -3217,7 +3054,9 @@
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:MarkStackSize in place of "
"-XX:CMSMarkStackSize or -XX:G1MarkStackSize in the future\n");
- FLAG_SET_CMDLINE(size_t, MarkStackSize, stack_size);
+ if (FLAG_SET_CMDLINE(size_t, MarkStackSize, stack_size) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (match_option(option, "-XX:CMSMarkStackSizeMax=", &tail)) {
julong max_stack_size = 0;
ArgsRange errcode = parse_memory_size(tail, &max_stack_size, 1);
@@ -3231,7 +3070,9 @@
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:MarkStackSizeMax in place of "
"-XX:CMSMarkStackSizeMax in the future\n");
- FLAG_SET_CMDLINE(size_t, MarkStackSizeMax, max_stack_size);
+ if (FLAG_SET_CMDLINE(size_t, MarkStackSizeMax, max_stack_size) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (match_option(option, "-XX:ParallelMarkingThreads=", &tail) ||
match_option(option, "-XX:ParallelCMSThreads=", &tail)) {
uintx conc_threads = 0;
@@ -3243,7 +3084,9 @@
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:ConcGCThreads in place of "
"-XX:ParallelMarkingThreads or -XX:ParallelCMSThreads in the future\n");
- FLAG_SET_CMDLINE(uintx, ConcGCThreads, conc_threads);
+ if (FLAG_SET_CMDLINE(uint, ConcGCThreads, conc_threads) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (match_option(option, "-XX:MaxDirectMemorySize=", &tail)) {
julong max_direct_memory_size = 0;
ArgsRange errcode = parse_memory_size(tail, &max_direct_memory_size, 0);
@@ -3254,7 +3097,9 @@
describe_range_error(errcode);
return JNI_EINVAL;
}
- FLAG_SET_CMDLINE(size_t, MaxDirectMemorySize, max_direct_memory_size);
+ if (FLAG_SET_CMDLINE(size_t, MaxDirectMemorySize, max_direct_memory_size) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
#if !INCLUDE_MANAGEMENT
} else if (match_option(option, "-XX:+ManagementServer")) {
jio_fprintf(defaultStream::error_stream(),
@@ -3263,11 +3108,15 @@
#endif // INCLUDE_MANAGEMENT
// CreateMinidumpOnCrash is removed, and replaced by CreateCoredumpOnCrash
} else if (match_option(option, "-XX:+CreateMinidumpOnCrash")) {
- FLAG_SET_CMDLINE(bool, CreateCoredumpOnCrash, true);
+ if (FLAG_SET_CMDLINE(bool, CreateCoredumpOnCrash, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
jio_fprintf(defaultStream::output_stream(),
"CreateMinidumpOnCrash is replaced by CreateCoredumpOnCrash: CreateCoredumpOnCrash is on\n");
} else if (match_option(option, "-XX:-CreateMinidumpOnCrash")) {
- FLAG_SET_CMDLINE(bool, CreateCoredumpOnCrash, false);
+ if (FLAG_SET_CMDLINE(bool, CreateCoredumpOnCrash, false) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
jio_fprintf(defaultStream::output_stream(),
"CreateMinidumpOnCrash is replaced by CreateCoredumpOnCrash: CreateCoredumpOnCrash is off\n");
} else if (match_option(option, "-XX:", &tail)) { // -XX:xxxx
@@ -3287,9 +3136,15 @@
// -Xshare:on
// -XX:+TraceClassPaths
if (PrintSharedArchiveAndExit) {
- FLAG_SET_CMDLINE(bool, UseSharedSpaces, true);
- FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true);
- FLAG_SET_CMDLINE(bool, TraceClassPaths, true);
+ if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, TraceClassPaths, true) != Flag::SUCCESS) {
+ return JNI_EINVAL;
+ }
}
// Change the default value for flags which have different default values
@@ -3696,6 +3551,10 @@
jint Arguments::parse(const JavaVMInitArgs* args) {
+ // Initialize ranges and constraints
+ CommandLineFlagRangeList::init();
+ CommandLineFlagConstraintList::init();
+
// Remaining part of option string
const char* tail;
@@ -4030,6 +3889,15 @@
return JNI_OK;
}
+// Any custom code post the final range and constraint check
+// can be done here. We pass a flag that specifies whether
+// the check passed successfully
+void Arguments::post_final_range_and_constraint_check(bool check_passed) {
+ // This does not set the flag itself, but stores the value in a safe place for later usage.
+ _min_heap_free_ratio = MinHeapFreeRatio;
+ _max_heap_free_ratio = MaxHeapFreeRatio;
+}
+
int Arguments::PropertyList_count(SystemProperty* pl) {
int count = 0;
while(pl != NULL) {
--- a/hotspot/src/share/vm/runtime/arguments.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/arguments.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -328,7 +328,6 @@
// Tiered
static void set_tiered_flags();
- static int get_min_number_of_compiler_threads();
// CMS/ParNew garbage collectors
static void set_parnew_gc_flags();
static void set_cms_and_parnew_gc_flags();
@@ -384,14 +383,6 @@
return is_bad_option(option, ignore, NULL);
}
- static bool is_percentage(uintx val) {
- return val <= 100;
- }
-
- static bool verify_interval(uintx val, uintx min,
- uintx max, const char* name);
- static bool verify_min_value(intx val, intx min, const char* name);
- static bool verify_percentage(uintx value, const char* name);
static void describe_range_error(ArgsRange errcode);
static ArgsRange check_memory_size(julong size, julong min_size);
static ArgsRange parse_memory_size(const char* s, julong* long_arg,
@@ -447,6 +438,9 @@
static char* SharedArchivePath;
public:
+ // Tiered
+ static int get_min_number_of_compiler_threads();
+
// Scale compile thresholds
// Returns threshold scaled with CompileThresholdScaling
static intx scaled_compile_threshold(intx threshold, double scale);
@@ -465,26 +459,18 @@
static jint apply_ergo();
// Adjusts the arguments after the OS have adjusted the arguments
static jint adjust_after_os();
+ // Set any arguments that need to be set after the final range and constraint check
+ static void post_final_range_and_constraint_check(bool check_passed);
static void set_gc_specific_flags();
static inline bool gc_selected(); // whether a gc has been selected
static void select_gc_ergonomically();
- // Verifies that the given value will fit as a MinHeapFreeRatio. If not, an error
- // message is returned in the provided buffer.
- static bool verify_MinHeapFreeRatio(FormatBuffer<80>& err_msg, uintx min_heap_free_ratio);
-
- // Verifies that the given value will fit as a MaxHeapFreeRatio. If not, an error
- // message is returned in the provided buffer.
- static bool verify_MaxHeapFreeRatio(FormatBuffer<80>& err_msg, uintx max_heap_free_ratio);
-
// Check for consistency in the selection of the garbage collector.
static bool check_gc_consistency(); // Check user-selected gc
static void check_deprecated_gc_flags();
// Check consistency or otherwise of VM argument settings
static bool check_vm_args_consistency();
- // Check stack pages settings
- static bool check_stack_pages();
// Used by os_solaris
static bool process_settings_file(const char* file_name, bool should_exist, jboolean ignore_unrecognized);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
+#include "gc/shared/referenceProcessor.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/commandLineFlagConstraintList.hpp"
+#include "runtime/commandLineFlagConstraintsCompiler.hpp"
+#include "runtime/commandLineFlagConstraintsGC.hpp"
+#include "runtime/commandLineFlagConstraintsRuntime.hpp"
+#include "runtime/os.hpp"
+#include "utilities/macros.hpp"
+
+class CommandLineFlagConstraint_bool : public CommandLineFlagConstraint {
+ CommandLineFlagConstraintFunc_bool _constraint;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagConstraint_bool(const char* name, CommandLineFlagConstraintFunc_bool func) : CommandLineFlagConstraint(name) {
+ _constraint=func;
+ }
+
+ Flag::Error apply_bool(bool* value, bool verbose) {
+ return _constraint(verbose, value);
+ }
+};
+
+class CommandLineFlagConstraint_int : public CommandLineFlagConstraint {
+ CommandLineFlagConstraintFunc_int _constraint;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagConstraint_int(const char* name, CommandLineFlagConstraintFunc_int func) : CommandLineFlagConstraint(name) {
+ _constraint=func;
+ }
+
+ Flag::Error apply_int(int* value, bool verbose) {
+ return _constraint(verbose, value);
+ }
+};
+
+class CommandLineFlagConstraint_intx : public CommandLineFlagConstraint {
+ CommandLineFlagConstraintFunc_intx _constraint;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagConstraint_intx(const char* name, CommandLineFlagConstraintFunc_intx func) : CommandLineFlagConstraint(name) {
+ _constraint=func;
+ }
+
+ Flag::Error apply_intx(intx* value, bool verbose) {
+ return _constraint(verbose, value);
+ }
+};
+
+class CommandLineFlagConstraint_uint : public CommandLineFlagConstraint {
+ CommandLineFlagConstraintFunc_uint _constraint;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagConstraint_uint(const char* name, CommandLineFlagConstraintFunc_uint func) : CommandLineFlagConstraint(name) {
+ _constraint=func;
+ }
+
+ Flag::Error apply_uint(uint* value, bool verbose) {
+ return _constraint(verbose, value);
+ }
+};
+
+class CommandLineFlagConstraint_uintx : public CommandLineFlagConstraint {
+ CommandLineFlagConstraintFunc_uintx _constraint;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagConstraint_uintx(const char* name, CommandLineFlagConstraintFunc_uintx func) : CommandLineFlagConstraint(name) {
+ _constraint=func;
+ }
+
+ Flag::Error apply_uintx(uintx* value, bool verbose) {
+ return _constraint(verbose, value);
+ }
+};
+
+class CommandLineFlagConstraint_uint64_t : public CommandLineFlagConstraint {
+ CommandLineFlagConstraintFunc_uint64_t _constraint;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagConstraint_uint64_t(const char* name, CommandLineFlagConstraintFunc_uint64_t func) : CommandLineFlagConstraint(name) {
+ _constraint=func;
+ }
+
+ Flag::Error apply_uint64_t(uint64_t* value, bool verbose) {
+ return _constraint(verbose, value);
+ }
+};
+
+class CommandLineFlagConstraint_size_t : public CommandLineFlagConstraint {
+ CommandLineFlagConstraintFunc_size_t _constraint;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagConstraint_size_t(const char* name, CommandLineFlagConstraintFunc_size_t func) : CommandLineFlagConstraint(name) {
+ _constraint=func;
+ }
+
+ Flag::Error apply_size_t(size_t* value, bool verbose) {
+ return _constraint(verbose, value);
+ }
+};
+
+class CommandLineFlagConstraint_double : public CommandLineFlagConstraint {
+ CommandLineFlagConstraintFunc_double _constraint;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagConstraint_double(const char* name, CommandLineFlagConstraintFunc_double func) : CommandLineFlagConstraint(name) {
+ _constraint=func;
+ }
+
+ Flag::Error apply_double(double* value, bool verbose) {
+ return _constraint(verbose, value);
+ }
+};
+
+// No constraint emitting
+void emit_constraint_no(...) { /* NOP */ }
+
+// No constraint emitting if function argument is NOT provided
+void emit_constraint_bool(const char* /*name*/) { /* NOP */ }
+void emit_constraint_ccstr(const char* /*name*/) { /* NOP */ }
+void emit_constraint_ccstrlist(const char* /*name*/) { /* NOP */ }
+void emit_constraint_int(const char* /*name*/) { /* NOP */ }
+void emit_constraint_intx(const char* /*name*/) { /* NOP */ }
+void emit_constraint_uint(const char* /*name*/) { /* NOP */ }
+void emit_constraint_uintx(const char* /*name*/) { /* NOP */ }
+void emit_constraint_uint64_t(const char* /*name*/) { /* NOP */ }
+void emit_constraint_size_t(const char* /*name*/) { /* NOP */ }
+void emit_constraint_double(const char* /*name*/) { /* NOP */ }
+
+// CommandLineFlagConstraint emitting code functions if function argument is provided
+void emit_constraint_bool(const char* name, CommandLineFlagConstraintFunc_bool func) {
+ CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_bool(name, func));
+}
+void emit_constraint_int(const char* name, CommandLineFlagConstraintFunc_int func) {
+ CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_int(name, func));
+}
+void emit_constraint_intx(const char* name, CommandLineFlagConstraintFunc_intx func) {
+ CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_intx(name, func));
+}
+void emit_constraint_uint(const char* name, CommandLineFlagConstraintFunc_uint func) {
+ CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint(name, func));
+}
+void emit_constraint_uintx(const char* name, CommandLineFlagConstraintFunc_uintx func) {
+ CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uintx(name, func));
+}
+void emit_constraint_uint64_t(const char* name, CommandLineFlagConstraintFunc_uint64_t func) {
+ CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_uint64_t(name, func));
+}
+void emit_constraint_size_t(const char* name, CommandLineFlagConstraintFunc_size_t func) {
+ CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_size_t(name, func));
+}
+void emit_constraint_double(const char* name, CommandLineFlagConstraintFunc_double func) {
+ CommandLineFlagConstraintList::add(new CommandLineFlagConstraint_double(name, func));
+}
+
+// Generate code to call emit_constraint_xxx function
+#define EMIT_CONSTRAINT_PRODUCT_FLAG(type, name, value, doc) ); emit_constraint_##type(#name
+#define EMIT_CONSTRAINT_COMMERCIAL_FLAG(type, name, value, doc) ); emit_constraint_##type(#name
+#define EMIT_CONSTRAINT_DIAGNOSTIC_FLAG(type, name, value, doc) ); emit_constraint_##type(#name
+#define EMIT_CONSTRAINT_EXPERIMENTAL_FLAG(type, name, value, doc) ); emit_constraint_##type(#name
+#define EMIT_CONSTRAINT_MANAGEABLE_FLAG(type, name, value, doc) ); emit_constraint_##type(#name
+#define EMIT_CONSTRAINT_PRODUCT_RW_FLAG(type, name, value, doc) ); emit_constraint_##type(#name
+#define EMIT_CONSTRAINT_PD_PRODUCT_FLAG(type, name, doc) ); emit_constraint_##type(#name
+#define EMIT_CONSTRAINT_DEVELOPER_FLAG(type, name, value, doc) ); emit_constraint_##type(#name
+#define EMIT_CONSTRAINT_PD_DEVELOPER_FLAG(type, name, doc) ); emit_constraint_##type(#name
+#define EMIT_CONSTRAINT_NOTPRODUCT_FLAG(type, name, value, doc) ); emit_constraint_##type(#name
+#define EMIT_CONSTRAINT_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_constraint_##type(#name
+
+// Generate func argument to pass into emit_constraint_xxx functions
+#define EMIT_CONSTRAINT_CHECK(func) , func
+
+// the "name" argument must be a string literal
+#define INITIAL_CONTRAINTS_SIZE 16
+GrowableArray<CommandLineFlagConstraint*>* CommandLineFlagConstraintList::_constraints = NULL;
+
+// Check the ranges of all flags that have them or print them out and exit if requested
+void CommandLineFlagConstraintList::init(void) {
+
+ _constraints = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<CommandLineFlagConstraint*>(INITIAL_CONTRAINTS_SIZE, true);
+
+ emit_constraint_no(NULL RUNTIME_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
+ EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
+ EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
+ EMIT_CONSTRAINT_MANAGEABLE_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_RW_FLAG,
+ EMIT_CONSTRAINT_LP64_PRODUCT_FLAG,
+ IGNORE_RANGE,
+ EMIT_CONSTRAINT_CHECK));
+
+ EMIT_CONSTRAINTS_FOR_GLOBALS_EXT
+
+ emit_constraint_no(NULL ARCH_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
+ EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
+ EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
+ IGNORE_RANGE,
+ EMIT_CONSTRAINT_CHECK));
+
+#ifdef COMPILER1
+ emit_constraint_no(NULL C1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
+ EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
+ IGNORE_RANGE,
+ EMIT_CONSTRAINT_CHECK));
+#endif // COMPILER1
+
+#ifdef COMPILER2
+ emit_constraint_no(NULL C2_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
+ EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
+ EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
+ IGNORE_RANGE,
+ EMIT_CONSTRAINT_CHECK));
+#endif // COMPILER2
+
+#ifndef INCLUDE_ALL_GCS
+ emit_constraint_no(NULL G1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PD_DEVELOPER_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_PD_PRODUCT_FLAG,
+ EMIT_CONSTRAINT_DIAGNOSTIC_FLAG,
+ EMIT_CONSTRAINT_EXPERIMENTAL_FLAG,
+ EMIT_CONSTRAINT_NOTPRODUCT_FLAG,
+ EMIT_CONSTRAINT_MANAGEABLE_FLAG,
+ EMIT_CONSTRAINT_PRODUCT_RW_FLAG,
+ IGNORE_RANGE,
+ EMIT_CONSTRAINT_CHECK));
+#endif // INCLUDE_ALL_GCS
+}
+
+CommandLineFlagConstraint* CommandLineFlagConstraintList::find(const char* name) {
+ CommandLineFlagConstraint* found = NULL;
+ for (int i=0; i<length(); i++) {
+ CommandLineFlagConstraint* constraint = at(i);
+ if (strcmp(constraint->name(), name) == 0) {
+ found = constraint;
+ break;
+ }
+ }
+ return found;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP
+#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP
+
+#include "runtime/globals.hpp"
+#include "utilities/growableArray.hpp"
+
+/*
+ * Here we have a mechanism for extracting constraints (as custom functions) for flags,
+ * which otherwise can not be expressed via simple range check, specified in flag macro tables.
+ *
+ * An example of a constraint is "flag1 < flag2" where both flag1 and flag2 can change.
+ *
+ * See runtime "runtime/commandLineFlagConstraintsCompiler.hpp",
+ * "runtime/commandLineFlagConstraintsGC.hpp" and
+ * "runtime/commandLineFlagConstraintsRuntime.hpp" for the functions themselves.
+ */
+
+typedef Flag::Error (*CommandLineFlagConstraintFunc_bool)(bool verbose, bool* value);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_int)(bool verbose, int* value);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_intx)(bool verbose, intx* value);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_uint)(bool verbose, uint* value);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_uintx)(bool verbose, uintx* value);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_uint64_t)(bool verbose, uint64_t* value);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_size_t)(bool verbose, size_t* value);
+typedef Flag::Error (*CommandLineFlagConstraintFunc_double)(bool verbose, double* value);
+
+class CommandLineFlagConstraint : public CHeapObj<mtInternal> {
+private:
+ const char* _name;
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagConstraint(const char* name) { _name=name; };
+ ~CommandLineFlagConstraint() {};
+ const char* name() { return _name; }
+ virtual Flag::Error apply_bool(bool* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_int(int* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_intx(intx* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_uint(uint* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_uintx(uintx* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_uint64_t(uint64_t* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_size_t(size_t* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+ virtual Flag::Error apply_double(double* value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; };
+};
+
+class CommandLineFlagConstraintList : public AllStatic {
+private:
+ static GrowableArray<CommandLineFlagConstraint*>* _constraints;
+public:
+ static void init();
+ static int length() { return (_constraints != NULL) ? _constraints->length() : 0; }
+ static CommandLineFlagConstraint* at(int i) { return (_constraints != NULL) ? _constraints->at(i) : NULL; }
+ static CommandLineFlagConstraint* find(const char* name);
+ static void add(CommandLineFlagConstraint* constraint) { _constraints->append(constraint); }
+};
+
+#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTLIST_HPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/commandLineFlagConstraintsCompiler.hpp"
+#include "runtime/globals.hpp"
+#include "utilities/defaultStream.hpp"
+
+Flag::Error AliasLevelConstraintFunc(bool verbose, intx* value) {
+ if (CommandLineFlags::finishedInitializing() == true) {
+ if ((*value <= 1) && (Arguments::mode() == Arguments::_comp)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "AliasLevel (" INTX_FORMAT ") is not compatible "
+ "with -Xcomp \n",
+ *value);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+ return Flag::SUCCESS;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsCompiler.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP
+#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP
+
+#include "runtime/globals.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+/*
+ * Here we have compiler arguments constraints functions, which are called automatically
+ * whenever flag's value changes. If the constraint fails the function should return
+ * an appropriate error value.
+ */
+
+Flag::Error AliasLevelConstraintFunc(bool verbose, intx* value);
+
+#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSCOMPILER_HPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/commandLineFlagConstraintsGC.hpp"
+#include "runtime/globals.hpp"
+#include "utilities/defaultStream.hpp"
+
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1_globals.hpp"
+#endif // INCLUDE_ALL_GCS
+#ifdef COMPILER1
+#include "c1/c1_globals.hpp"
+#endif // COMPILER1
+#ifdef COMPILER2
+#include "opto/c2_globals.hpp"
+#endif // COMPILER2
+
+Flag::Error MinHeapFreeRatioConstraintFunc(bool verbose, uintx* value) {
+ if ((CommandLineFlags::finishedInitializing()) && (*value > MaxHeapFreeRatio)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "MinHeapFreeRatio (" UINTX_FORMAT ") must be less than or "
+ "equal to MaxHeapFreeRatio (" UINTX_FORMAT ")\n",
+ *value, MaxHeapFreeRatio);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error MaxHeapFreeRatioConstraintFunc(bool verbose, uintx* value) {
+ if ((CommandLineFlags::finishedInitializing()) && (*value < MinHeapFreeRatio)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "MaxHeapFreeRatio (" UINTX_FORMAT ") must be greater than or "
+ "equal to MinHeapFreeRatio (" UINTX_FORMAT ")\n",
+ *value, MinHeapFreeRatio);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error MinMetaspaceFreeRatioConstraintFunc(bool verbose, uintx* value) {
+ if ((CommandLineFlags::finishedInitializing()) && (*value > MaxMetaspaceFreeRatio)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "MinMetaspaceFreeRatio (" UINTX_FORMAT ") must be less than or "
+ "equal to MaxMetaspaceFreeRatio (" UINTX_FORMAT ")\n",
+ *value, MaxMetaspaceFreeRatio);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error MaxMetaspaceFreeRatioConstraintFunc(bool verbose, uintx* value) {
+ if ((CommandLineFlags::finishedInitializing()) && (*value < MinMetaspaceFreeRatio)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "MaxMetaspaceFreeRatio (" UINTX_FORMAT ") must be greater than or "
+ "equal to MinMetaspaceFreeRatio (" UINTX_FORMAT ")\n",
+ *value, MinMetaspaceFreeRatio);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+// GC workaround for "-XX:+UseConcMarkSweepGC"
+// which sets InitialTenuringThreshold to 7 but leaves MaxTenuringThreshold remaining at 6
+// and therefore would invalidate the constraint
+#define UseConcMarkSweepGCWorkaroundIfNeeded(initial, max) { \
+ if ((initial == 7) && (max == 6)) { \
+ return Flag::SUCCESS; \
+ } \
+}
+
+Flag::Error InitialTenuringThresholdConstraintFunc(bool verbose, uintx* value) {
+ UseConcMarkSweepGCWorkaroundIfNeeded(*value, MaxTenuringThreshold);
+
+ if ((CommandLineFlags::finishedInitializing()) && (*value > MaxTenuringThreshold)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "InitialTenuringThreshold (" UINTX_FORMAT ") must be less than or "
+ "equal to MaxTenuringThreshold (" UINTX_FORMAT ")\n",
+ *value, MaxTenuringThreshold);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error MaxTenuringThresholdConstraintFunc(bool verbose, uintx* value) {
+ UseConcMarkSweepGCWorkaroundIfNeeded(InitialTenuringThreshold, *value);
+
+ if ((CommandLineFlags::finishedInitializing()) && (*value < InitialTenuringThreshold)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "MaxTenuringThreshold (" UINTX_FORMAT ") must be greater than or "
+ "equal to InitialTenuringThreshold (" UINTX_FORMAT ")\n",
+ *value, InitialTenuringThreshold);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+#if INCLUDE_ALL_GCS
+
+Flag::Error G1NewSizePercentConstraintFunc(bool verbose, uintx* value) {
+ if ((CommandLineFlags::finishedInitializing()) && (*value > G1MaxNewSizePercent)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "G1NewSizePercent (" UINTX_FORMAT ") must be less than or "
+ "equal to G1MaxNewSizePercent (" UINTX_FORMAT ")\n",
+ *value, G1MaxNewSizePercent);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error G1MaxNewSizePercentConstraintFunc(bool verbose, uintx* value) {
+ if ((CommandLineFlags::finishedInitializing()) && (*value < G1NewSizePercent)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "G1MaxNewSizePercent (" UINTX_FORMAT ") must be greater than or "
+ "equal to G1NewSizePercent (" UINTX_FORMAT ")\n",
+ *value, G1NewSizePercent);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+#endif // INCLUDE_ALL_GCS
+
+Flag::Error CMSOldPLABMinConstraintFunc(bool verbose, size_t* value) {
+ if ((CommandLineFlags::finishedInitializing()) && (*value > CMSOldPLABMax)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "CMSOldPLABMin (" SIZE_FORMAT ") must be less than or "
+ "equal to CMSOldPLABMax (" SIZE_FORMAT ")\n",
+ *value, CMSOldPLABMax);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error CMSPrecleanDenominatorConstraintFunc(bool verbose, uintx* value) {
+ if ((CommandLineFlags::finishedInitializing()) && (*value <= CMSPrecleanNumerator)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "CMSPrecleanDenominator (" UINTX_FORMAT ") must be strickly greater than "
+ "CMSPrecleanNumerator (" UINTX_FORMAT ")\n",
+ *value, CMSPrecleanNumerator);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error CMSPrecleanNumeratorConstraintFunc(bool verbose, uintx* value) {
+ if ((CommandLineFlags::finishedInitializing()) && (*value > (CMSPrecleanDenominator - 1))) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "CMSPrecleanNumerator (" UINTX_FORMAT ") must be less than or "
+ "equal to CMSPrecleanDenominator - 1 (" UINTX_FORMAT ")\n", *value,
+ CMSPrecleanDenominator - 1);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
+Flag::Error SurvivorAlignmentInBytesConstraintFunc(bool verbose, intx* value) {
+ if (CommandLineFlags::finishedInitializing()) {
+ if (*value != 0) {
+ if (!is_power_of_2(*value)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be power of 2\n",
+ *value);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ if (*value < ObjectAlignmentInBytes) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be greater than or "
+ "equal to ObjectAlignmentInBytes (" INTX_FORMAT ") \n",
+ *value, ObjectAlignmentInBytes);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+ }
+ return Flag::SUCCESS;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSGC_HPP
+#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSGC_HPP
+
+#include "runtime/globals.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+/*
+ * Here we have GC arguments constraints functions, which are called automatically
+ * whenever flag's value changes. If the constraint fails the function should return
+ * an appropriate error value.
+ */
+
+Flag::Error MinHeapFreeRatioConstraintFunc(bool verbose, uintx* value);
+Flag::Error MaxHeapFreeRatioConstraintFunc(bool verbose, uintx* value);
+
+Flag::Error MinMetaspaceFreeRatioConstraintFunc(bool verbose, uintx* value);
+Flag::Error MaxMetaspaceFreeRatioConstraintFunc(bool verbose, uintx* value);
+
+Flag::Error InitialTenuringThresholdConstraintFunc(bool verbose, uintx* value);
+Flag::Error MaxTenuringThresholdConstraintFunc(bool verbose, uintx* value);
+
+#if INCLUDE_ALL_GCS
+Flag::Error G1NewSizePercentConstraintFunc(bool verbose, uintx* value);
+Flag::Error G1MaxNewSizePercentConstraintFunc(bool verbose, uintx* value);
+#endif // INCLUDE_ALL_GCS
+
+Flag::Error CMSOldPLABMinConstraintFunc(bool verbose, size_t* value);
+
+Flag::Error CMSPrecleanDenominatorConstraintFunc(bool verbose, uintx* value);
+Flag::Error CMSPrecleanNumeratorConstraintFunc(bool verbose, uintx* value);
+
+Flag::Error SurvivorAlignmentInBytesConstraintFunc(bool verbose, intx* value);
+
+#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSGC_HPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/commandLineFlagConstraintsRuntime.hpp"
+#include "runtime/globals.hpp"
+#include "utilities/defaultStream.hpp"
+
+Flag::Error ObjectAlignmentInBytesConstraintFunc(bool verbose, intx* value) {
+ if (!is_power_of_2(*value)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "ObjectAlignmentInBytes=" INTX_FORMAT " must be power of 2\n",
+ *value);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ // In case page size is very small.
+ if (*value >= (intx)os::vm_page_size()) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "ObjectAlignmentInBytes=" INTX_FORMAT " must be less than page size " INTX_FORMAT "\n",
+ *value, (intx)os::vm_page_size());
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
+// Need to enforce the padding not to break the existing field alignments.
+// It is sufficient to check against the largest type size.
+Flag::Error ContendedPaddingWidthConstraintFunc(bool verbose, intx* value) {
+ if ((*value != 0) && ((*value % BytesPerLong) != 0)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "ContendedPaddingWidth=" INTX_FORMAT " must be a multiple of %d\n",
+ *value, BytesPerLong);
+ }
+ return Flag::VIOLATES_CONSTRAINT;
+ } else {
+ return Flag::SUCCESS;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsRuntime.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP
+#define SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP
+
+#include "runtime/globals.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+/*
+ * Here we have runtime arguments constraints functions, which are called automatically
+ * whenever flag's value changes. If the constraint fails the function should return
+ * an appropriate error value.
+ */
+
+Flag::Error ObjectAlignmentInBytesConstraintFunc(bool verbose, intx* value);
+
+Flag::Error ContendedPaddingWidthConstraintFunc(bool verbose, intx* value);
+
+#endif /* SHARE_VM_RUNTIME_COMMANDLINEFLAGCONSTRAINTSRUNTIME_HPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
+#include "gc/shared/referenceProcessor.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/commandLineFlagRangeList.hpp"
+#include "runtime/os.hpp"
+#include "utilities/defaultStream.hpp"
+#include "utilities/macros.hpp"
+
+class CommandLineFlagRange_int : public CommandLineFlagRange {
+ int _min;
+ int _max;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagRange_int(const char* name, int min, int max) : CommandLineFlagRange(name) {
+ _min=min, _max=max;
+ }
+
+ Flag::Error check_int(int value, bool verbose = true) {
+ if ((value < _min) || (value > _max)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "int %s=%d is outside the allowed range [ %d ... %d ]\n",
+ name(), value, _min, _max);
+ }
+ return Flag::OUT_OF_BOUNDS;
+ } else {
+ return Flag::SUCCESS;
+ }
+ }
+
+ void print(outputStream* st) {
+ st->print("[ %-25d ... %25d ]", _min, _max);
+ }
+};
+
+class CommandLineFlagRange_intx : public CommandLineFlagRange {
+ intx _min;
+ intx _max;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagRange_intx(const char* name, intx min, intx max) : CommandLineFlagRange(name) {
+ _min=min, _max=max;
+ }
+
+ Flag::Error check_intx(intx value, bool verbose = true) {
+ if ((value < _min) || (value > _max)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "intx %s=" INTX_FORMAT " is outside the allowed range [ " INTX_FORMAT " ... " INTX_FORMAT " ]\n",
+ name(), value, _min, _max);
+ }
+ return Flag::OUT_OF_BOUNDS;
+ } else {
+ return Flag::SUCCESS;
+ }
+ }
+
+ void print(outputStream* st) {
+ st->print("[ "INTX_FORMAT_W(-25)" ... "INTX_FORMAT_W(25)" ]", _min, _max);
+ }
+};
+
+class CommandLineFlagRange_uint : public CommandLineFlagRange {
+ uint _min;
+ uint _max;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagRange_uint(const char* name, uint min, uint max) : CommandLineFlagRange(name) {
+ _min=min, _max=max;
+ }
+
+ Flag::Error check_uint(uint value, bool verbose = true) {
+ if ((value < _min) || (value > _max)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "uintx %s=%u is outside the allowed range [ %u ... %u ]\n",
+ name(), value, _min, _max);
+ }
+ return Flag::OUT_OF_BOUNDS;
+ } else {
+ return Flag::SUCCESS;
+ }
+ }
+
+ void print(outputStream* st) {
+ st->print("[ %-25u ... %25u ]", _min, _max);
+ }
+};
+
+class CommandLineFlagRange_uintx : public CommandLineFlagRange {
+ uintx _min;
+ uintx _max;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagRange_uintx(const char* name, uintx min, uintx max) : CommandLineFlagRange(name) {
+ _min=min, _max=max;
+ }
+
+ Flag::Error check_uintx(uintx value, bool verbose = true) {
+ if ((value < _min) || (value > _max)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "uintx %s=" UINTX_FORMAT " is outside the allowed range [ " UINTX_FORMAT " ... " UINTX_FORMAT " ]\n",
+ name(), value, _min, _max);
+ }
+ return Flag::OUT_OF_BOUNDS;
+ } else {
+ return Flag::SUCCESS;
+ }
+ }
+
+ void print(outputStream* st) {
+ st->print("[ "UINTX_FORMAT_W(-25)" ... "UINTX_FORMAT_W(25)" ]", _min, _max);
+ }
+};
+
+class CommandLineFlagRange_uint64_t : public CommandLineFlagRange {
+ uint64_t _min;
+ uint64_t _max;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagRange_uint64_t(const char* name, uint64_t min, uint64_t max) : CommandLineFlagRange(name) {
+ _min=min, _max=max;
+ }
+
+ Flag::Error check_uint64_t(uint64_t value, bool verbose = true) {
+ if ((value < _min) || (value > _max)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "uint64_t %s=" UINT64_FORMAT " is outside the allowed range [ " UINT64_FORMAT " ... " UINT64_FORMAT " ]\n",
+ name(), value, _min, _max);
+ }
+ return Flag::OUT_OF_BOUNDS;
+ } else {
+ return Flag::SUCCESS;
+ }
+ }
+
+ void print(outputStream* st) {
+ st->print("[ "UINT64_FORMAT_W(-25)" ... "UINT64_FORMAT_W(25)" ]", _min, _max);
+ }
+};
+
+class CommandLineFlagRange_size_t : public CommandLineFlagRange {
+ size_t _min;
+ size_t _max;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagRange_size_t(const char* name, size_t min, size_t max) : CommandLineFlagRange(name) {
+ _min=min, _max=max;
+ }
+
+ Flag::Error check_size_t(size_t value, bool verbose = true) {
+ if ((value < _min) || (value > _max)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "size_t %s=" SIZE_FORMAT " is outside the allowed range [ " SIZE_FORMAT " ... " SIZE_FORMAT " ]\n",
+ name(), value, _min, _max);
+ }
+ return Flag::OUT_OF_BOUNDS;
+ } else {
+ return Flag::SUCCESS;
+ }
+ }
+
+ void print(outputStream* st) {
+ st->print("[ "SIZE_FORMAT_W(-25)" ... "SIZE_FORMAT_W(25)" ]", _min, _max);
+ }
+};
+
+class CommandLineFlagRange_double : public CommandLineFlagRange {
+ double _min;
+ double _max;
+
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagRange_double(const char* name, double min, double max) : CommandLineFlagRange(name) {
+ _min=min, _max=max;
+ }
+
+ Flag::Error check_double(double value, bool verbose = true) {
+ if ((value < _min) || (value > _max)) {
+ if (verbose == true) {
+ jio_fprintf(defaultStream::error_stream(),
+ "double %s=%f is outside the allowed range [ %f ... %f ]\n",
+ name(), value, _min, _max);
+ }
+ return Flag::OUT_OF_BOUNDS;
+ } else {
+ return Flag::SUCCESS;
+ }
+ }
+
+ void print(outputStream* st) {
+ st->print("[ %-25.3f ... %25.3f ]", _min, _max);
+ }
+};
+
+// No constraint emitting
+void emit_range_no(...) { /* NOP */ }
+
+// No constraint emitting if function argument is NOT provided
+void emit_range_bool(const char* /*name*/) { /* NOP */ }
+void emit_range_ccstr(const char* /*name*/) { /* NOP */ }
+void emit_range_ccstrlist(const char* /*name*/) { /* NOP */ }
+void emit_range_int(const char* /*name*/) { /* NOP */ }
+void emit_range_intx(const char* /*name*/) { /* NOP */ }
+void emit_range_uint(const char* /*name*/) { /* NOP */ }
+void emit_range_uintx(const char* /*name*/) { /* NOP */ }
+void emit_range_uint64_t(const char* /*name*/) { /* NOP */ }
+void emit_range_size_t(const char* /*name*/) { /* NOP */ }
+void emit_range_double(const char* /*name*/) { /* NOP */ }
+
+// CommandLineFlagRange emitting code functions if range arguments are provided
+void emit_range_intx(const char* name, intx min, intx max) {
+ CommandLineFlagRangeList::add(new CommandLineFlagRange_intx(name, min, max));
+}
+void emit_range_uintx(const char* name, uintx min, uintx max) {
+ CommandLineFlagRangeList::add(new CommandLineFlagRange_uintx(name, min, max));
+}
+void emit_range_uint64_t(const char* name, uint64_t min, uint64_t max) {
+ CommandLineFlagRangeList::add(new CommandLineFlagRange_uint64_t(name, min, max));
+}
+void emit_range_size_t(const char* name, size_t min, size_t max) {
+ CommandLineFlagRangeList::add(new CommandLineFlagRange_size_t(name, min, max));
+}
+void emit_range_double(const char* name, double min, double max) {
+ CommandLineFlagRangeList::add(new CommandLineFlagRange_double(name, min, max));
+}
+
+// Generate code to call emit_range_xxx function
+#define EMIT_RANGE_PRODUCT_FLAG(type, name, value, doc) ); emit_range_##type(#name
+#define EMIT_RANGE_COMMERCIAL_FLAG(type, name, value, doc) ); emit_range_##type(#name
+#define EMIT_RANGE_DIAGNOSTIC_FLAG(type, name, value, doc) ); emit_range_##type(#name
+#define EMIT_RANGE_EXPERIMENTAL_FLAG(type, name, value, doc) ); emit_range_##type(#name
+#define EMIT_RANGE_MANAGEABLE_FLAG(type, name, value, doc) ); emit_range_##type(#name
+#define EMIT_RANGE_PRODUCT_RW_FLAG(type, name, value, doc) ); emit_range_##type(#name
+#define EMIT_RANGE_PD_PRODUCT_FLAG(type, name, doc) ); emit_range_##type(#name
+#define EMIT_RANGE_DEVELOPER_FLAG(type, name, value, doc) ); emit_range_##type(#name
+#define EMIT_RANGE_PD_DEVELOPER_FLAG(type, name, doc) ); emit_range_##type(#name
+#define EMIT_RANGE_NOTPRODUCT_FLAG(type, name, value, doc) ); emit_range_##type(#name
+#define EMIT_RANGE_LP64_PRODUCT_FLAG(type, name, value, doc) ); emit_range_##type(#name
+
+// Generate func argument to pass into emit_range_xxx functions
+#define EMIT_RANGE_CHECK(a, b) , a, b
+
+#define INITIAL_RANGES_SIZE 128
+GrowableArray<CommandLineFlagRange*>* CommandLineFlagRangeList::_ranges = NULL;
+
+// Check the ranges of all flags that have them
+void CommandLineFlagRangeList::init(void) {
+
+ _ranges = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<CommandLineFlagRange*>(INITIAL_RANGES_SIZE, true);
+
+ emit_range_no(NULL RUNTIME_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
+ EMIT_RANGE_PD_DEVELOPER_FLAG,
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_PD_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_EXPERIMENTAL_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_MANAGEABLE_FLAG,
+ EMIT_RANGE_PRODUCT_RW_FLAG,
+ EMIT_RANGE_LP64_PRODUCT_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT) );
+
+ EMIT_RANGES_FOR_GLOBALS_EXT
+
+ emit_range_no(NULL ARCH_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_EXPERIMENTAL_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT));
+
+#ifdef COMPILER1
+ emit_range_no(NULL C1_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
+ EMIT_RANGE_PD_DEVELOPER_FLAG,
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_PD_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT));
+#endif // COMPILER1
+
+#ifdef COMPILER2
+ emit_range_no(NULL C2_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
+ EMIT_RANGE_PD_DEVELOPER_FLAG,
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_PD_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_EXPERIMENTAL_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT));
+#endif // COMPILER2
+
+#if INCLUDE_ALL_GCS
+ emit_range_no(NULL G1_FLAGS(EMIT_RANGE_DEVELOPER_FLAG,
+ EMIT_RANGE_PD_DEVELOPER_FLAG,
+ EMIT_RANGE_PRODUCT_FLAG,
+ EMIT_RANGE_PD_PRODUCT_FLAG,
+ EMIT_RANGE_DIAGNOSTIC_FLAG,
+ EMIT_RANGE_EXPERIMENTAL_FLAG,
+ EMIT_RANGE_NOTPRODUCT_FLAG,
+ EMIT_RANGE_MANAGEABLE_FLAG,
+ EMIT_RANGE_PRODUCT_RW_FLAG,
+ EMIT_RANGE_CHECK,
+ IGNORE_CONSTRAINT));
+#endif // INCLUDE_ALL_GCS
+}
+
+CommandLineFlagRange* CommandLineFlagRangeList::find(const char* name) {
+ CommandLineFlagRange* found = NULL;
+ for (int i=0; i<length(); i++) {
+ CommandLineFlagRange* range = at(i);
+ if (strcmp(range->name(), name) == 0) {
+ found = range;
+ break;
+ }
+ }
+ return found;
+}
+
+void CommandLineFlagRangeList::print(const char* name, outputStream* st, bool unspecified) {
+ CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
+ if (range != NULL) {
+ range->print(st);
+ } else if (unspecified == true) {
+ st->print("[ ... ]");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
+#define SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
+
+#include "runtime/globals.hpp"
+#include "utilities/growableArray.hpp"
+
+/*
+ * Here we have a mechanism for extracting ranges specified in flag macro tables.
+ *
+ * The specified ranges are used to verify that flags have valid values.
+ *
+ * An example of a range is "min <= flag <= max". Both "min" and "max" must be
+ * constant and can not change. If either "min" or "max" can change,
+ * then we need to use constraint instead.
+ */
+
+class CommandLineFlagRange : public CHeapObj<mtInternal> {
+private:
+ const char* _name;
+public:
+ // the "name" argument must be a string literal
+ CommandLineFlagRange(const char* name) { _name=name; }
+ ~CommandLineFlagRange() {}
+ const char* name() { return _name; }
+ virtual Flag::Error check_int(int value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }
+ virtual Flag::Error check_intx(intx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }
+ virtual Flag::Error check_uint(uint value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }
+ virtual Flag::Error check_uintx(uintx value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }
+ virtual Flag::Error check_uint64_t(uint64_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }
+ virtual Flag::Error check_size_t(size_t value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }
+ virtual Flag::Error check_double(double value, bool verbose = true) { ShouldNotReachHere(); return Flag::ERR_OTHER; }
+ virtual void print(outputStream* st) { ; }
+};
+
+class CommandLineFlagRangeList : public AllStatic {
+ static GrowableArray<CommandLineFlagRange*>* _ranges;
+public:
+ static void init();
+ static void add_globals_ext();
+ static int length() { return (_ranges != NULL) ? _ranges->length() : 0; }
+ static CommandLineFlagRange* at(int i) { return (_ranges != NULL) ? _ranges->at(i) : NULL; }
+ static CommandLineFlagRange* find(const char* name);
+ static void add(CommandLineFlagRange* range) { _ranges->append(range); }
+ static void print(const char* name, outputStream* st, bool unspecified = false);
+};
+
+#endif // SHARE_VM_RUNTIME_COMMANDLINEFLAGRANGELIST_HPP
--- a/hotspot/src/share/vm/runtime/frame.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/frame.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -307,11 +307,6 @@
void interpreter_frame_verify_monitor(BasicObjectLock* value) const;
- // Tells whether the current interpreter_frame frame pointer
- // corresponds to the old compiled/deoptimized fp
- // The receiver used to be a top level frame
- bool interpreter_frame_equals_unpacked_fp(intptr_t* fp);
-
// Return/result value from this interpreter frame
// If the method return type is T_OBJECT or T_ARRAY populates oop_result
// For other (non-T_VOID) the appropriate field in the jvalue is populated
--- a/hotspot/src/share/vm/runtime/globals.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/globals.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -28,7 +28,10 @@
#include "runtime/arguments.hpp"
#include "runtime/globals.hpp"
#include "runtime/globals_extension.hpp"
+#include "runtime/commandLineFlagConstraintList.hpp"
+#include "runtime/commandLineFlagRangeList.hpp"
#include "runtime/os.hpp"
+#include "runtime/sharedRuntime.hpp"
#include "trace/tracing.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
@@ -48,24 +51,38 @@
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
-RUNTIME_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_EXPERIMENTAL_FLAG, \
+RUNTIME_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
+ MATERIALIZE_PD_DEVELOPER_FLAG, \
+ MATERIALIZE_PRODUCT_FLAG, \
+ MATERIALIZE_PD_PRODUCT_FLAG, \
+ MATERIALIZE_DIAGNOSTIC_FLAG, \
+ MATERIALIZE_EXPERIMENTAL_FLAG, \
MATERIALIZE_NOTPRODUCT_FLAG, \
- MATERIALIZE_MANAGEABLE_FLAG, MATERIALIZE_PRODUCT_RW_FLAG, \
- MATERIALIZE_LP64_PRODUCT_FLAG)
+ MATERIALIZE_MANAGEABLE_FLAG, \
+ MATERIALIZE_PRODUCT_RW_FLAG, \
+ MATERIALIZE_LP64_PRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
-RUNTIME_OS_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, \
- MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG)
+RUNTIME_OS_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
+ MATERIALIZE_PD_DEVELOPER_FLAG, \
+ MATERIALIZE_PRODUCT_FLAG, \
+ MATERIALIZE_PD_PRODUCT_FLAG, \
+ MATERIALIZE_DIAGNOSTIC_FLAG, \
+ MATERIALIZE_NOTPRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
-ARCH_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, \
- MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_EXPERIMENTAL_FLAG, \
- MATERIALIZE_NOTPRODUCT_FLAG)
+ARCH_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
+ MATERIALIZE_PRODUCT_FLAG, \
+ MATERIALIZE_DIAGNOSTIC_FLAG, \
+ MATERIALIZE_EXPERIMENTAL_FLAG, \
+ MATERIALIZE_NOTPRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
MATERIALIZE_FLAGS_EXT
-
static bool is_product_build() {
#ifdef PRODUCT
return true;
@@ -331,69 +348,86 @@
#define FORMAT_BUFFER_LEN 16
PRAGMA_FORMAT_NONLITERAL_IGNORED_EXTERNAL
-void Flag::print_on(outputStream* st, bool withComments) {
+void Flag::print_on(outputStream* st, bool withComments, bool printRanges) {
// Don't print notproduct and develop flags in a product build.
if (is_constant_in_binary()) {
return;
}
- st->print("%9s %-40s %c= ", _type, _name, (!is_default() ? ':' : ' '));
+ if (!printRanges) {
+
+ st->print("%9s %-40s %c= ", _type, _name, (!is_default() ? ':' : ' '));
- if (is_bool()) {
- st->print("%-16s", get_bool() ? "true" : "false");
- }
- if (is_int()) {
- st->print("%-16d", get_int());
- }
- if (is_uint()) {
- st->print("%-16u", get_uint());
- }
- if (is_intx()) {
- st->print("%-16ld", get_intx());
- }
- if (is_uintx()) {
- st->print("%-16lu", get_uintx());
- }
- if (is_uint64_t()) {
- st->print("%-16lu", get_uint64_t());
- }
- if (is_size_t()) {
- st->print(SIZE_FORMAT_W(-16), get_size_t());
- }
- if (is_double()) {
- st->print("%-16f", get_double());
+ if (is_bool()) {
+ st->print("%-16s", get_bool() ? "true" : "false");
+ } else if (is_int()) {
+ st->print("%-16d", get_int());
+ } else if (is_uint()) {
+ st->print("%-16u", get_uint());
+ } else if (is_intx()) {
+ st->print("%-16ld", get_intx());
+ } else if (is_uintx()) {
+ st->print("%-16lu", get_uintx());
+ } else if (is_uint64_t()) {
+ st->print("%-16lu", get_uint64_t());
+ } else if (is_size_t()) {
+ st->print(SIZE_FORMAT_W(-16), get_size_t());
+ } else if (is_double()) {
+ st->print("%-16f", get_double());
+ } else if (is_ccstr()) {
+ const char* cp = get_ccstr();
+ if (cp != NULL) {
+ const char* eol;
+ while ((eol = strchr(cp, '\n')) != NULL) {
+ char format_buffer[FORMAT_BUFFER_LEN];
+ size_t llen = pointer_delta(eol, cp, sizeof(char));
+ jio_snprintf(format_buffer, FORMAT_BUFFER_LEN,
+ "%%." SIZE_FORMAT "s", llen);
+ PRAGMA_DIAG_PUSH
+ PRAGMA_FORMAT_NONLITERAL_IGNORED_INTERNAL
+ st->print(format_buffer, cp);
+ PRAGMA_DIAG_POP
+ st->cr();
+ cp = eol+1;
+ st->print("%5s %-35s += ", "", _name);
+ }
+ st->print("%-16s", cp);
+ }
+ else st->print("%-16s", "");
+ }
+
+ st->print("%-20s", " ");
+ print_kind(st);
+
+#ifndef PRODUCT
+ if (withComments) {
+ st->print("%s", _doc);
+ }
+#endif
+
+ st->cr();
+
+ } else if (!is_bool() && !is_ccstr()) {
+
+ if (printRanges) {
+
+ st->print("%9s %-50s ", _type, _name);
+
+ CommandLineFlagRangeList::print(_name, st, true);
+
+ st->print(" %-20s", " ");
+ print_kind(st);
+
+#ifndef PRODUCT
+ if (withComments) {
+ st->print("%s", _doc);
+ }
+#endif
+
+ st->cr();
+
+ }
}
- if (is_ccstr()) {
- const char* cp = get_ccstr();
- if (cp != NULL) {
- const char* eol;
- while ((eol = strchr(cp, '\n')) != NULL) {
- char format_buffer[FORMAT_BUFFER_LEN];
- size_t llen = pointer_delta(eol, cp, sizeof(char));
- jio_snprintf(format_buffer, FORMAT_BUFFER_LEN,
- "%%." SIZE_FORMAT "s", llen);
-PRAGMA_DIAG_PUSH
-PRAGMA_FORMAT_NONLITERAL_IGNORED_INTERNAL
- st->print(format_buffer, cp);
-PRAGMA_DIAG_POP
- st->cr();
- cp = eol+1;
- st->print("%5s %-35s += ", "", _name);
- }
- st->print("%-16s", cp);
- }
- else st->print("%-16s", "");
- }
-
- st->print("%-20s", " ");
- print_kind(st);
-
- if (withComments) {
-#ifndef PRODUCT
- st->print("%s", _doc);
-#endif
- }
- st->cr();
}
void Flag::print_kind(outputStream* st) {
@@ -531,21 +565,75 @@
#define SHARK_NOTPRODUCT_FLAG_STRUCT( type, name, value, doc) { #type, XSTR(name), NAME(name), NOT_PRODUCT_ARG(doc) Flag::Flags(Flag::DEFAULT | Flag::KIND_SHARK | Flag::KIND_NOT_PRODUCT) },
static Flag flagTable[] = {
- RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_EXPERIMENTAL_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT, RUNTIME_MANAGEABLE_FLAG_STRUCT, RUNTIME_PRODUCT_RW_FLAG_STRUCT, RUNTIME_LP64_PRODUCT_FLAG_STRUCT)
- RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT)
+ RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \
+ RUNTIME_PD_DEVELOP_FLAG_STRUCT, \
+ RUNTIME_PRODUCT_FLAG_STRUCT, \
+ RUNTIME_PD_PRODUCT_FLAG_STRUCT, \
+ RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \
+ RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \
+ RUNTIME_NOTPRODUCT_FLAG_STRUCT, \
+ RUNTIME_MANAGEABLE_FLAG_STRUCT, \
+ RUNTIME_PRODUCT_RW_FLAG_STRUCT, \
+ RUNTIME_LP64_PRODUCT_FLAG_STRUCT, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
+ RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \
+ RUNTIME_PD_DEVELOP_FLAG_STRUCT, \
+ RUNTIME_PRODUCT_FLAG_STRUCT, \
+ RUNTIME_PD_PRODUCT_FLAG_STRUCT, \
+ RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \
+ RUNTIME_NOTPRODUCT_FLAG_STRUCT, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
#if INCLUDE_ALL_GCS
- G1_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, RUNTIME_PD_DEVELOP_FLAG_STRUCT, RUNTIME_PRODUCT_FLAG_STRUCT, RUNTIME_PD_PRODUCT_FLAG_STRUCT, RUNTIME_DIAGNOSTIC_FLAG_STRUCT, RUNTIME_EXPERIMENTAL_FLAG_STRUCT, RUNTIME_NOTPRODUCT_FLAG_STRUCT, RUNTIME_MANAGEABLE_FLAG_STRUCT, RUNTIME_PRODUCT_RW_FLAG_STRUCT)
+ G1_FLAGS(RUNTIME_DEVELOP_FLAG_STRUCT, \
+ RUNTIME_PD_DEVELOP_FLAG_STRUCT, \
+ RUNTIME_PRODUCT_FLAG_STRUCT, \
+ RUNTIME_PD_PRODUCT_FLAG_STRUCT, \
+ RUNTIME_DIAGNOSTIC_FLAG_STRUCT, \
+ RUNTIME_EXPERIMENTAL_FLAG_STRUCT, \
+ RUNTIME_NOTPRODUCT_FLAG_STRUCT, \
+ RUNTIME_MANAGEABLE_FLAG_STRUCT, \
+ RUNTIME_PRODUCT_RW_FLAG_STRUCT, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
#endif // INCLUDE_ALL_GCS
#ifdef COMPILER1
- C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, C1_PD_DEVELOP_FLAG_STRUCT, C1_PRODUCT_FLAG_STRUCT, C1_PD_PRODUCT_FLAG_STRUCT, C1_DIAGNOSTIC_FLAG_STRUCT, C1_NOTPRODUCT_FLAG_STRUCT)
-#endif
+ C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, \
+ C1_PD_DEVELOP_FLAG_STRUCT, \
+ C1_PRODUCT_FLAG_STRUCT, \
+ C1_PD_PRODUCT_FLAG_STRUCT, \
+ C1_DIAGNOSTIC_FLAG_STRUCT, \
+ C1_NOTPRODUCT_FLAG_STRUCT, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
+#endif // COMPILER1
#ifdef COMPILER2
- C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, C2_PD_DEVELOP_FLAG_STRUCT, C2_PRODUCT_FLAG_STRUCT, C2_PD_PRODUCT_FLAG_STRUCT, C2_DIAGNOSTIC_FLAG_STRUCT, C2_EXPERIMENTAL_FLAG_STRUCT, C2_NOTPRODUCT_FLAG_STRUCT)
-#endif
+ C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, \
+ C2_PD_DEVELOP_FLAG_STRUCT, \
+ C2_PRODUCT_FLAG_STRUCT, \
+ C2_PD_PRODUCT_FLAG_STRUCT, \
+ C2_DIAGNOSTIC_FLAG_STRUCT, \
+ C2_EXPERIMENTAL_FLAG_STRUCT, \
+ C2_NOTPRODUCT_FLAG_STRUCT, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
+#endif // COMPILER2
#ifdef SHARK
- SHARK_FLAGS(SHARK_DEVELOP_FLAG_STRUCT, SHARK_PD_DEVELOP_FLAG_STRUCT, SHARK_PRODUCT_FLAG_STRUCT, SHARK_PD_PRODUCT_FLAG_STRUCT, SHARK_DIAGNOSTIC_FLAG_STRUCT, SHARK_NOTPRODUCT_FLAG_STRUCT)
-#endif
- ARCH_FLAGS(ARCH_DEVELOP_FLAG_STRUCT, ARCH_PRODUCT_FLAG_STRUCT, ARCH_DIAGNOSTIC_FLAG_STRUCT, ARCH_EXPERIMENTAL_FLAG_STRUCT, ARCH_NOTPRODUCT_FLAG_STRUCT)
+ SHARK_FLAGS(SHARK_DEVELOP_FLAG_STRUCT, \
+ SHARK_PD_DEVELOP_FLAG_STRUCT, \
+ SHARK_PRODUCT_FLAG_STRUCT, \
+ SHARK_PD_PRODUCT_FLAG_STRUCT, \
+ SHARK_DIAGNOSTIC_FLAG_STRUCT, \
+ SHARK_NOTPRODUCT_FLAG_STRUCT)
+#endif // SHARK
+ ARCH_FLAGS(ARCH_DEVELOP_FLAG_STRUCT, \
+ ARCH_PRODUCT_FLAG_STRUCT, \
+ ARCH_DIAGNOSTIC_FLAG_STRUCT, \
+ ARCH_EXPERIMENTAL_FLAG_STRUCT, \
+ ARCH_NOTPRODUCT_FLAG_STRUCT, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
FLAGTABLE_EXT
{0, NULL, NULL}
};
@@ -566,7 +654,7 @@
// Found a matching entry.
// Don't report notproduct and develop flags in product builds.
if (current->is_constant_in_binary()) {
- return (return_flag == true ? current : NULL);
+ return (return_flag ? current : NULL);
}
// Report locked flags only if allowed.
if (!(current->is_unlocked() || current->is_unlocker())) {
@@ -661,8 +749,7 @@
}
template<class E, class T>
-static void trace_flag_changed(const char* name, const T old_value, const T new_value, const Flag::Flags origin)
-{
+static void trace_flag_changed(const char* name, const T old_value, const T new_value, const Flag::Flags origin) {
E e;
e.set_name(name);
e.set_old_value(old_value);
@@ -671,242 +758,395 @@
e.commit();
}
-bool CommandLineFlags::boolAt(const char* name, size_t len, bool* value, bool allow_locked, bool return_flag) {
- Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
- if (result == NULL) return false;
- if (!result->is_bool()) return false;
- *value = result->get_bool();
- return true;
+static Flag::Error get_status_error(Flag::Error status_range, Flag::Error status_constraint) {
+ if (status_range != Flag::SUCCESS) {
+ return status_range;
+ } else if (status_constraint != Flag::SUCCESS) {
+ return status_constraint;
+ } else {
+ return Flag::SUCCESS;
+ }
}
-bool CommandLineFlags::boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin) {
+static Flag::Error apply_constraint_and_check_range_bool(const char* name, bool* new_value, bool verbose = true) {
+ Flag::Error status = Flag::SUCCESS;
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name);
+ if (constraint != NULL) {
+ status = constraint->apply_bool(new_value, verbose);
+ }
+ return status;
+}
+
+Flag::Error CommandLineFlags::boolAt(const char* name, size_t len, bool* value, bool allow_locked, bool return_flag) {
+ Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_bool()) return Flag::WRONG_FORMAT;
+ *value = result->get_bool();
+ return Flag::SUCCESS;
+}
+
+Flag::Error CommandLineFlags::boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return false;
- if (!result->is_bool()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_bool()) return Flag::WRONG_FORMAT;
+ Flag::Error check = apply_constraint_and_check_range_bool(name, value, !CommandLineFlags::finishedInitializing());
+ if (check != Flag::SUCCESS) return check;
bool old_value = result->get_bool();
trace_flag_changed<EventBooleanFlagChanged, bool>(name, old_value, *value, origin);
result->set_bool(*value);
*value = old_value;
result->set_origin(origin);
- return true;
+ return Flag::SUCCESS;
}
-void CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin) {
+Flag::Error CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type");
+ Flag::Error check = apply_constraint_and_check_range_bool(faddr->_name, &value);
+ if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventBooleanFlagChanged, bool>(faddr->_name, faddr->get_bool(), value, origin);
faddr->set_bool(value);
faddr->set_origin(origin);
+ return Flag::SUCCESS;
}
-bool CommandLineFlags::intAt(const char* name, size_t len, int* value, bool allow_locked, bool return_flag) {
- Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
- if (result == NULL) return false;
- if (!result->is_int()) return false;
- *value = result->get_int();
- return true;
+static Flag::Error apply_constraint_and_check_range_int(const char* name, int* new_value, bool verbose = true) {
+ Flag::Error range_status = Flag::SUCCESS;
+ CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
+ if (range != NULL) {
+ range_status = range->check_int(*new_value, verbose);
+ }
+ Flag::Error constraint_status = Flag::SUCCESS;
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name);
+ if (constraint != NULL) {
+ constraint_status = constraint->apply_int(new_value, verbose);
+ }
+ return get_status_error(range_status, constraint_status);
}
-bool CommandLineFlags::intAtPut(const char* name, size_t len, int* value, Flag::Flags origin) {
+Flag::Error CommandLineFlags::intAt(const char* name, size_t len, int* value, bool allow_locked, bool return_flag) {
+ Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_int()) return Flag::WRONG_FORMAT;
+ *value = result->get_int();
+ return Flag::SUCCESS;
+}
+
+Flag::Error CommandLineFlags::intAtPut(const char* name, size_t len, int* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return false;
- if (!result->is_int()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_int()) return Flag::WRONG_FORMAT;
+ Flag::Error check = apply_constraint_and_check_range_int(name, value, !CommandLineFlags::finishedInitializing());
+ if (check != Flag::SUCCESS) return check;
int old_value = result->get_int();
trace_flag_changed<EventIntFlagChanged, s4>(name, old_value, *value, origin);
result->set_int(*value);
*value = old_value;
result->set_origin(origin);
- return true;
+ return Flag::SUCCESS;
}
-void CommandLineFlagsEx::intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin) {
+Flag::Error CommandLineFlagsEx::intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_int(), "wrong flag type");
trace_flag_changed<EventIntFlagChanged, s4>(faddr->_name, faddr->get_int(), value, origin);
faddr->set_int(value);
faddr->set_origin(origin);
+ return Flag::SUCCESS;
}
-bool CommandLineFlags::uintAt(const char* name, size_t len, uint* value, bool allow_locked, bool return_flag) {
- Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
- if (result == NULL) return false;
- if (!result->is_uint()) return false;
- *value = result->get_uint();
- return true;
+static Flag::Error apply_constraint_and_check_range_uint(const char* name, uint* new_value, bool verbose = true) {
+ Flag::Error range_status = Flag::SUCCESS;
+ CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
+ if (range != NULL) {
+ range_status = range->check_uint(*new_value, verbose);
+ }
+ Flag::Error constraint_status = Flag::SUCCESS;
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name);
+ if (constraint != NULL) {
+ constraint_status = constraint->apply_uint(new_value, verbose);
+ }
+ return get_status_error(range_status, constraint_status);
}
-bool CommandLineFlags::uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin) {
+Flag::Error CommandLineFlags::uintAt(const char* name, size_t len, uint* value, bool allow_locked, bool return_flag) {
+ Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_uint()) return Flag::WRONG_FORMAT;
+ *value = result->get_uint();
+ return Flag::SUCCESS;
+}
+
+Flag::Error CommandLineFlags::uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return false;
- if (!result->is_uint()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_uint()) return Flag::WRONG_FORMAT;
+ Flag::Error check = apply_constraint_and_check_range_uint(name, value, !CommandLineFlags::finishedInitializing());
+ if (check != Flag::SUCCESS) return check;
uint old_value = result->get_uint();
trace_flag_changed<EventUnsignedIntFlagChanged, u4>(name, old_value, *value, origin);
result->set_uint(*value);
*value = old_value;
result->set_origin(origin);
- return true;
+ return Flag::SUCCESS;
}
-void CommandLineFlagsEx::uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin) {
+Flag::Error CommandLineFlagsEx::uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uint(), "wrong flag type");
trace_flag_changed<EventUnsignedIntFlagChanged, u4>(faddr->_name, faddr->get_uint(), value, origin);
faddr->set_uint(value);
faddr->set_origin(origin);
+ return Flag::SUCCESS;
+}
+
+Flag::Error CommandLineFlags::intxAt(const char* name, size_t len, intx* value, bool allow_locked, bool return_flag) {
+ Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_intx()) return Flag::WRONG_FORMAT;
+ *value = result->get_intx();
+ return Flag::SUCCESS;
}
-bool CommandLineFlags::intxAt(const char* name, size_t len, intx* value, bool allow_locked, bool return_flag) {
- Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
- if (result == NULL) return false;
- if (!result->is_intx()) return false;
- *value = result->get_intx();
- return true;
+static Flag::Error apply_constraint_and_check_range_intx(const char* name, intx* new_value, bool verbose = true) {
+ Flag::Error range_status = Flag::SUCCESS;
+ CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
+ if (range != NULL) {
+ range_status = range->check_intx(*new_value, verbose);
+ }
+ Flag::Error constraint_status = Flag::SUCCESS;
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name);
+ if (constraint != NULL) {
+ constraint_status = constraint->apply_intx(new_value, verbose);
+ }
+ return get_status_error(range_status, constraint_status);
}
-bool CommandLineFlags::intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin) {
+Flag::Error CommandLineFlags::intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return false;
- if (!result->is_intx()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_intx()) return Flag::WRONG_FORMAT;
+ Flag::Error check = apply_constraint_and_check_range_intx(name, value, !CommandLineFlags::finishedInitializing());
+ if (check != Flag::SUCCESS) return check;
intx old_value = result->get_intx();
- trace_flag_changed<EventLongFlagChanged, s8>(name, old_value, *value, origin);
+ trace_flag_changed<EventLongFlagChanged, intx>(name, old_value, *value, origin);
result->set_intx(*value);
*value = old_value;
result->set_origin(origin);
- return true;
+ return Flag::SUCCESS;
}
-void CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin) {
+Flag::Error CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type");
- trace_flag_changed<EventLongFlagChanged, s8>(faddr->_name, faddr->get_intx(), value, origin);
+ Flag::Error check = apply_constraint_and_check_range_intx(faddr->_name, &value);
+ if (check != Flag::SUCCESS) return check;
+ trace_flag_changed<EventLongFlagChanged, intx>(faddr->_name, faddr->get_intx(), value, origin);
faddr->set_intx(value);
faddr->set_origin(origin);
+ return Flag::SUCCESS;
}
-bool CommandLineFlags::uintxAt(const char* name, size_t len, uintx* value, bool allow_locked, bool return_flag) {
+Flag::Error CommandLineFlags::uintxAt(const char* name, size_t len, uintx* value, bool allow_locked, bool return_flag) {
Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
- if (result == NULL) return false;
- if (!result->is_uintx()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_uintx()) return Flag::WRONG_FORMAT;
*value = result->get_uintx();
- return true;
+ return Flag::SUCCESS;
}
-bool CommandLineFlags::uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin) {
+static Flag::Error apply_constraint_and_check_range_uintx(const char* name, uintx* new_value, bool verbose = true) {
+ Flag::Error range_status = Flag::SUCCESS;
+ CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
+ if (range != NULL) {
+ range_status = range->check_uintx(*new_value, verbose);
+ }
+ Flag::Error constraint_status = Flag::SUCCESS;
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name);
+ if (constraint != NULL) {
+ constraint_status = constraint->apply_uintx(new_value, verbose);
+ }
+ return get_status_error(range_status, constraint_status);
+}
+
+Flag::Error CommandLineFlags::uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return false;
- if (!result->is_uintx()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_uintx()) return Flag::WRONG_FORMAT;
+ Flag::Error check = apply_constraint_and_check_range_uintx(name, value, !CommandLineFlags::finishedInitializing());
+ if (check != Flag::SUCCESS) return check;
uintx old_value = result->get_uintx();
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
result->set_uintx(*value);
*value = old_value;
result->set_origin(origin);
- return true;
+ return Flag::SUCCESS;
}
-void CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin) {
+Flag::Error CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type");
+ Flag::Error check = apply_constraint_and_check_range_uintx(faddr->_name, &value);
+ if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_uintx(), value, origin);
faddr->set_uintx(value);
faddr->set_origin(origin);
+ return Flag::SUCCESS;
+}
+
+Flag::Error CommandLineFlags::uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked, bool return_flag) {
+ Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_uint64_t()) return Flag::WRONG_FORMAT;
+ *value = result->get_uint64_t();
+ return Flag::SUCCESS;
}
-bool CommandLineFlags::uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked, bool return_flag) {
- Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
- if (result == NULL) return false;
- if (!result->is_uint64_t()) return false;
- *value = result->get_uint64_t();
- return true;
+static Flag::Error apply_constraint_and_check_range_uint64_t(const char* name, uint64_t* new_value, bool verbose = true) {
+ Flag::Error range_status = Flag::SUCCESS;
+ CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
+ if (range != NULL) {
+ range_status = range->check_uint64_t(*new_value, verbose);
+ }
+ Flag::Error constraint_status = Flag::SUCCESS;
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name);
+ if (constraint != NULL) {
+ constraint_status = constraint->apply_uint64_t(new_value, verbose);
+ }
+ return get_status_error(range_status, constraint_status);
}
-bool CommandLineFlags::uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin) {
+Flag::Error CommandLineFlags::uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return false;
- if (!result->is_uint64_t()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_uint64_t()) return Flag::WRONG_FORMAT;
+ Flag::Error check = apply_constraint_and_check_range_uint64_t(name, value, !CommandLineFlags::finishedInitializing());
+ if (check != Flag::SUCCESS) return check;
uint64_t old_value = result->get_uint64_t();
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
result->set_uint64_t(*value);
*value = old_value;
result->set_origin(origin);
- return true;
+ return Flag::SUCCESS;
}
-void CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin) {
+Flag::Error CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type");
+ Flag::Error check = apply_constraint_and_check_range_uint64_t(faddr->_name, &value);
+ if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_uint64_t(), value, origin);
faddr->set_uint64_t(value);
faddr->set_origin(origin);
+ return Flag::SUCCESS;
+}
+
+Flag::Error CommandLineFlags::size_tAt(const char* name, size_t len, size_t* value, bool allow_locked, bool return_flag) {
+ Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_size_t()) return Flag::WRONG_FORMAT;
+ *value = result->get_size_t();
+ return Flag::SUCCESS;
}
-bool CommandLineFlags::size_tAt(const char* name, size_t len, size_t* value, bool allow_locked, bool return_flag) {
- Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
- if (result == NULL) return false;
- if (!result->is_size_t()) return false;
- *value = result->get_size_t();
- return true;
+static Flag::Error apply_constraint_and_check_range_size_t(const char* name, size_t* new_value, bool verbose = true) {
+ Flag::Error range_status = Flag::SUCCESS;
+ CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
+ if (range != NULL) {
+ range_status = range->check_size_t(*new_value, verbose);
+ }
+ Flag::Error constraint_status = Flag::SUCCESS;
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name);
+ if (constraint != NULL) {
+ constraint_status = constraint->apply_size_t(new_value, verbose);
+ }
+ return get_status_error(range_status, constraint_status);
}
-bool CommandLineFlags::size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin) {
+Flag::Error CommandLineFlags::size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return false;
- if (!result->is_size_t()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_size_t()) return Flag::WRONG_FORMAT;
+ Flag::Error check = apply_constraint_and_check_range_size_t(name, value, !CommandLineFlags::finishedInitializing());
+ if (check != Flag::SUCCESS) return check;
size_t old_value = result->get_size_t();
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
result->set_size_t(*value);
*value = old_value;
result->set_origin(origin);
- return true;
+ return Flag::SUCCESS;
}
-void CommandLineFlagsEx::size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin) {
+Flag::Error CommandLineFlagsEx::size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_size_t(), "wrong flag type");
+ Flag::Error check = apply_constraint_and_check_range_size_t(faddr->_name, &value);
+ if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_size_t(), value, origin);
faddr->set_size_t(value);
faddr->set_origin(origin);
+ return Flag::SUCCESS;
+}
+
+Flag::Error CommandLineFlags::doubleAt(const char* name, size_t len, double* value, bool allow_locked, bool return_flag) {
+ Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_double()) return Flag::WRONG_FORMAT;
+ *value = result->get_double();
+ return Flag::SUCCESS;
}
-bool CommandLineFlags::doubleAt(const char* name, size_t len, double* value, bool allow_locked, bool return_flag) {
- Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
- if (result == NULL) return false;
- if (!result->is_double()) return false;
- *value = result->get_double();
- return true;
+static Flag::Error apply_constraint_and_check_range_double(const char* name, double* new_value, bool verbose = true) {
+ Flag::Error range_status = Flag::SUCCESS;
+ CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
+ if (range != NULL) {
+ range_status = range->check_double(*new_value, verbose);
+ }
+ Flag::Error constraint_status = Flag::SUCCESS;
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::find(name);
+ if (constraint != NULL) {
+ constraint_status = constraint->apply_double(new_value, verbose);
+ }
+ return get_status_error(range_status, constraint_status);
}
-bool CommandLineFlags::doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin) {
+Flag::Error CommandLineFlags::doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return false;
- if (!result->is_double()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_double()) return Flag::WRONG_FORMAT;
+ Flag::Error check = apply_constraint_and_check_range_double(name, value, !CommandLineFlags::finishedInitializing());
+ if (check != Flag::SUCCESS) return check;
double old_value = result->get_double();
trace_flag_changed<EventDoubleFlagChanged, double>(name, old_value, *value, origin);
result->set_double(*value);
*value = old_value;
result->set_origin(origin);
- return true;
+ return Flag::SUCCESS;
}
-void CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) {
+Flag::Error CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_double(), "wrong flag type");
+ Flag::Error check = apply_constraint_and_check_range_double(faddr->_name, &value, !CommandLineFlags::finishedInitializing());
+ if (check != Flag::SUCCESS) return check;
trace_flag_changed<EventDoubleFlagChanged, double>(faddr->_name, faddr->get_double(), value, origin);
faddr->set_double(value);
faddr->set_origin(origin);
+ return Flag::SUCCESS;
}
-bool CommandLineFlags::ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked, bool return_flag) {
+Flag::Error CommandLineFlags::ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked, bool return_flag) {
Flag* result = Flag::find_flag(name, len, allow_locked, return_flag);
- if (result == NULL) return false;
- if (!result->is_ccstr()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_ccstr()) return Flag::WRONG_FORMAT;
*value = result->get_ccstr();
- return true;
+ return Flag::SUCCESS;
}
-bool CommandLineFlags::ccstrAtPut(const char* name, size_t len, ccstr* value, Flag::Flags origin) {
+Flag::Error CommandLineFlags::ccstrAtPut(const char* name, size_t len, ccstr* value, Flag::Flags origin) {
Flag* result = Flag::find_flag(name, len);
- if (result == NULL) return false;
- if (!result->is_ccstr()) return false;
+ if (result == NULL) return Flag::INVALID_FLAG;
+ if (!result->is_ccstr()) return Flag::WRONG_FORMAT;
ccstr old_value = result->get_ccstr();
trace_flag_changed<EventStringFlagChanged, const char*>(name, old_value, *value, origin);
char* new_value = NULL;
@@ -920,10 +1160,10 @@
}
*value = old_value;
result->set_origin(origin);
- return true;
+ return Flag::SUCCESS;
}
-void CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin) {
+Flag::Error CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type");
ccstr old_value = faddr->get_ccstr();
@@ -935,6 +1175,7 @@
FREE_C_HEAP_ARRAY(char, old_value);
}
faddr->set_origin(origin);
+ return Flag::SUCCESS;
}
extern "C" {
@@ -969,16 +1210,140 @@
FREE_C_HEAP_ARRAY(Flag*, array);
}
+bool CommandLineFlags::_finished_initializing = false;
+
+bool CommandLineFlags::check_all_ranges_and_constraints() {
+
+//#define PRINT_RANGES_AND_CONSTRAINTS_SIZES
+#ifdef PRINT_RANGES_AND_CONSTRAINTS_SIZES
+ {
+ size_t size_ranges = sizeof(CommandLineFlagRangeList);
+ for (int i=0; i<CommandLineFlagRangeList::length(); i++) {
+ size_ranges += sizeof(CommandLineFlagRange);
+ CommandLineFlagRange* range = CommandLineFlagRangeList::at(i);
+ const char* name = range->name();
+ Flag* flag = Flag::find_flag(name, strlen(name), true, true);
+ if (flag->is_intx()) {
+ size_ranges += 2*sizeof(intx);
+ size_ranges += sizeof(CommandLineFlagRange*);
+ } else if (flag->is_uintx()) {
+ size_ranges += 2*sizeof(uintx);
+ size_ranges += sizeof(CommandLineFlagRange*);
+ } else if (flag->is_uint64_t()) {
+ size_ranges += 2*sizeof(uint64_t);
+ size_ranges += sizeof(CommandLineFlagRange*);
+ } else if (flag->is_size_t()) {
+ size_ranges += 2*sizeof(size_t);
+ size_ranges += sizeof(CommandLineFlagRange*);
+ } else if (flag->is_double()) {
+ size_ranges += 2*sizeof(double);
+ size_ranges += sizeof(CommandLineFlagRange*);
+ }
+ }
+ fprintf(stderr, "Size of %d ranges: "SIZE_FORMAT" bytes\n",
+ CommandLineFlagRangeList::length(), size_ranges);
+ }
+ {
+ size_t size_constraints = sizeof(CommandLineFlagConstraintList);
+ for (int i=0; i<CommandLineFlagConstraintList::length(); i++) {
+ size_constraints += sizeof(CommandLineFlagConstraint);
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::at(i);
+ const char* name = constraint->name();
+ Flag* flag = Flag::find_flag(name, strlen(name), true, true);
+ if (flag->is_bool()) {
+ size_constraints += sizeof(CommandLineFlagConstraintFunc_bool);
+ size_constraints += sizeof(CommandLineFlagConstraint*);
+ } else if (flag->is_intx()) {
+ size_constraints += sizeof(CommandLineFlagConstraintFunc_intx);
+ size_constraints += sizeof(CommandLineFlagConstraint*);
+ } else if (flag->is_uintx()) {
+ size_constraints += sizeof(CommandLineFlagConstraintFunc_uintx);
+ size_constraints += sizeof(CommandLineFlagConstraint*);
+ } else if (flag->is_uint64_t()) {
+ size_constraints += sizeof(CommandLineFlagConstraintFunc_uint64_t);
+ size_constraints += sizeof(CommandLineFlagConstraint*);
+ } else if (flag->is_size_t()) {
+ size_constraints += sizeof(CommandLineFlagConstraintFunc_size_t);
+ size_constraints += sizeof(CommandLineFlagConstraint*);
+ } else if (flag->is_double()) {
+ size_constraints += sizeof(CommandLineFlagConstraintFunc_double);
+ size_constraints += sizeof(CommandLineFlagConstraint*);
+ }
+ }
+ fprintf(stderr, "Size of %d constraints: "SIZE_FORMAT" bytes\n",
+ CommandLineFlagConstraintList::length(), size_constraints);
+ }
+#endif // PRINT_RANGES_AND_CONSTRAINTS_SIZES
+
+ _finished_initializing = true;
+
+ bool status = true;
+ for (int i=0; i<CommandLineFlagRangeList::length(); i++) {
+ CommandLineFlagRange* range = CommandLineFlagRangeList::at(i);
+ const char* name = range->name();
+ Flag* flag = Flag::find_flag(name, strlen(name), true, true);
+ if (flag != NULL) {
+ if (flag->is_intx()) {
+ intx value = flag->get_intx();
+ if (range->check_intx(value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_uintx()) {
+ uintx value = flag->get_uintx();
+ if (range->check_uintx(value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_uint64_t()) {
+ uint64_t value = flag->get_uint64_t();
+ if (range->check_uint64_t(value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_size_t()) {
+ size_t value = flag->get_size_t();
+ if (range->check_size_t(value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_double()) {
+ double value = flag->get_double();
+ if (range->check_double(value, true) != Flag::SUCCESS) status = false;
+ }
+ }
+ }
+ for (int i=0; i<CommandLineFlagConstraintList::length(); i++) {
+ CommandLineFlagConstraint* constraint = CommandLineFlagConstraintList::at(i);
+ const char*name = constraint->name();
+ Flag* flag = Flag::find_flag(name, strlen(name), true, true);
+ if (flag != NULL) {
+ if (flag->is_bool()) {
+ bool value = flag->get_bool();
+ if (constraint->apply_bool(&value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_intx()) {
+ intx value = flag->get_intx();
+ if (constraint->apply_intx(&value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_uintx()) {
+ uintx value = flag->get_uintx();
+ if (constraint->apply_uintx(&value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_uint64_t()) {
+ uint64_t value = flag->get_uint64_t();
+ if (constraint->apply_uint64_t(&value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_size_t()) {
+ size_t value = flag->get_size_t();
+ if (constraint->apply_size_t(&value, true) != Flag::SUCCESS) status = false;
+ } else if (flag->is_double()) {
+ double value = flag->get_double();
+ if (constraint->apply_double(&value, true) != Flag::SUCCESS) status = false;
+ }
+ }
+ }
+
+ Arguments::post_final_range_and_constraint_check(status);
+
+ return status;
+}
+
#ifndef PRODUCT
-
void CommandLineFlags::verify() {
assert(Arguments::check_vm_args_consistency(), "Some flag settings conflict");
}
#endif // PRODUCT
-void CommandLineFlags::printFlags(outputStream* out, bool withComments) {
+#define ONLY_PRINT_PRODUCT_FLAGS
+
+void CommandLineFlags::printFlags(outputStream* out, bool withComments, bool printRanges) {
// Print the flags sorted by name
// note: this method is called before the thread structure is in place
// which means resource allocation cannot be used.
@@ -994,10 +1359,18 @@
qsort(array, length, sizeof(Flag*), compare_flags);
// Print
- out->print_cr("[Global flags]");
+ if (!printRanges) {
+ out->print_cr("[Global flags]");
+ } else {
+ out->print_cr("[Global flags ranges]");
+ }
+
for (size_t i = 0; i < length; i++) {
if (array[i]->is_unlocked()) {
- array[i]->print_on(out, withComments);
+#ifdef ONLY_PRINT_PRODUCT_FLAGS
+ if (!array[i]->is_notproduct() && !array[i]->is_develop())
+#endif // ONLY_PRINT_PRODUCT_FLAGS
+ array[i]->print_on(out, withComments, printRanges);
}
}
FREE_C_HEAP_ARRAY(Flag*, array);
--- a/hotspot/src/share/vm/runtime/globals.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/globals.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -258,6 +258,27 @@
KIND_MASK = ~VALUE_ORIGIN_MASK
};
+ enum Error {
+ // no error
+ SUCCESS = 0,
+ // flag name is missing
+ MISSING_NAME,
+ // flag value is missing
+ MISSING_VALUE,
+ // error parsing the textual form of the value
+ WRONG_FORMAT,
+ // flag is not writeable
+ NON_WRITABLE,
+ // flag value is outside of its bounds
+ OUT_OF_BOUNDS,
+ // flag value violates its constraint
+ VIOLATES_CONSTRAINT,
+ // there is no flag with the given name
+ INVALID_FLAG,
+ // other, unspecified error related to setting the flag
+ ERR_OTHER
+ };
+
const char* _type;
const char* _name;
void* _addr;
@@ -270,6 +291,7 @@
// number of flags
static size_t numFlags;
+ static Flag* find_flag(const char* name) { return find_flag(name, strlen(name), true, true); };
static Flag* find_flag(const char* name, size_t length, bool allow_locked = false, bool return_flag = false);
static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false);
@@ -345,9 +367,24 @@
void get_locked_message(char*, int) const;
void get_locked_message_ext(char*, int) const;
- void print_on(outputStream* st, bool withComments = false );
+ // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges
+ void print_on(outputStream* st, bool withComments = false, bool printRanges = false);
void print_kind(outputStream* st);
void print_as_flag(outputStream* st);
+
+ static const char* flag_error_str(Flag::Error error) {
+ switch (error) {
+ case Flag::MISSING_NAME: return "MISSING_NAME";
+ case Flag::MISSING_VALUE: return "MISSING_VALUE";
+ case Flag::NON_WRITABLE: return "NON_WRITABLE";
+ case Flag::OUT_OF_BOUNDS: return "OUT_OF_BOUNDS";
+ case Flag::VIOLATES_CONSTRAINT: return "VIOLATES_CONSTRAINT";
+ case Flag::INVALID_FLAG: return "INVALID_FLAG";
+ case Flag::ERR_OTHER: return "ERR_OTHER";
+ case Flag::SUCCESS: return "SUCCESS";
+ default: return "NULL";
+ }
+ }
};
// debug flags control various aspects of the VM and are global accessible
@@ -413,59 +450,67 @@
class CommandLineFlags {
- public:
- static bool boolAt(const char* name, size_t len, bool* value, bool allow_locked = false, bool return_flag = false);
- static bool boolAt(const char* name, bool* value, bool allow_locked = false, bool return_flag = false) { return boolAt(name, strlen(name), value, allow_locked, return_flag); }
- static bool boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin);
- static bool boolAtPut(const char* name, bool* value, Flag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); }
+ static bool _finished_initializing;
+public:
+ static Flag::Error boolAt(const char* name, size_t len, bool* value, bool allow_locked = false, bool return_flag = false);
+ static Flag::Error boolAt(const char* name, bool* value, bool allow_locked = false, bool return_flag = false) { return boolAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error boolAtPut(const char* name, size_t len, bool* value, Flag::Flags origin);
+ static Flag::Error boolAtPut(const char* name, bool* value, Flag::Flags origin) { return boolAtPut(name, strlen(name), value, origin); }
- static bool intAt(const char* name, size_t len, int* value, bool allow_locked = false, bool return_flag = false);
- static bool intAt(const char* name, int* value, bool allow_locked = false, bool return_flag = false) { return intAt(name, strlen(name), value, allow_locked, return_flag); }
- static bool intAtPut(const char* name, size_t len, int* value, Flag::Flags origin);
- static bool intAtPut(const char* name, int* value, Flag::Flags origin) { return intAtPut(name, strlen(name), value, origin); }
+ static Flag::Error intAt(const char* name, size_t len, int* value, bool allow_locked = false, bool return_flag = false);
+ static Flag::Error intAt(const char* name, int* value, bool allow_locked = false, bool return_flag = false) { return intAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error intAtPut(const char* name, size_t len, int* value, Flag::Flags origin);
+ static Flag::Error intAtPut(const char* name, int* value, Flag::Flags origin) { return intAtPut(name, strlen(name), value, origin); }
- static bool uintAt(const char* name, size_t len, uint* value, bool allow_locked = false, bool return_flag = false);
- static bool uintAt(const char* name, uint* value, bool allow_locked = false, bool return_flag = false) { return uintAt(name, strlen(name), value, allow_locked, return_flag); }
- static bool uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin);
- static bool uintAtPut(const char* name, uint* value, Flag::Flags origin) { return uintAtPut(name, strlen(name), value, origin); }
+ static Flag::Error uintAt(const char* name, size_t len, uint* value, bool allow_locked = false, bool return_flag = false);
+ static Flag::Error uintAt(const char* name, uint* value, bool allow_locked = false, bool return_flag = false) { return uintAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error uintAtPut(const char* name, size_t len, uint* value, Flag::Flags origin);
+ static Flag::Error uintAtPut(const char* name, uint* value, Flag::Flags origin) { return uintAtPut(name, strlen(name), value, origin); }
- static bool intxAt(const char* name, size_t len, intx* value, bool allow_locked = false, bool return_flag = false);
- static bool intxAt(const char* name, intx* value, bool allow_locked = false, bool return_flag = false) { return intxAt(name, strlen(name), value, allow_locked, return_flag); }
- static bool intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin);
- static bool intxAtPut(const char* name, intx* value, Flag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); }
+ static Flag::Error intxAt(const char* name, size_t len, intx* value, bool allow_locked = false, bool return_flag = false);
+ static Flag::Error intxAt(const char* name, intx* value, bool allow_locked = false, bool return_flag = false) { return intxAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error intxAtPut(const char* name, size_t len, intx* value, Flag::Flags origin);
+ static Flag::Error intxAtPut(const char* name, intx* value, Flag::Flags origin) { return intxAtPut(name, strlen(name), value, origin); }
- static bool uintxAt(const char* name, size_t len, uintx* value, bool allow_locked = false, bool return_flag = false);
- static bool uintxAt(const char* name, uintx* value, bool allow_locked = false, bool return_flag = false) { return uintxAt(name, strlen(name), value, allow_locked, return_flag); }
- static bool uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin);
- static bool uintxAtPut(const char* name, uintx* value, Flag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); }
+ static Flag::Error uintxAt(const char* name, size_t len, uintx* value, bool allow_locked = false, bool return_flag = false);
+ static Flag::Error uintxAt(const char* name, uintx* value, bool allow_locked = false, bool return_flag = false) { return uintxAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error uintxAtPut(const char* name, size_t len, uintx* value, Flag::Flags origin);
+ static Flag::Error uintxAtPut(const char* name, uintx* value, Flag::Flags origin) { return uintxAtPut(name, strlen(name), value, origin); }
- static bool size_tAt(const char* name, size_t len, size_t* value, bool allow_locked = false, bool return_flag = false);
- static bool size_tAt(const char* name, size_t* value, bool allow_locked = false, bool return_flag = false) { return size_tAt(name, strlen(name), value, allow_locked, return_flag); }
- static bool size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin);
- static bool size_tAtPut(const char* name, size_t* value, Flag::Flags origin) { return size_tAtPut(name, strlen(name), value, origin); }
+ static Flag::Error size_tAt(const char* name, size_t len, size_t* value, bool allow_locked = false, bool return_flag = false);
+ static Flag::Error size_tAt(const char* name, size_t* value, bool allow_locked = false, bool return_flag = false) { return size_tAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error size_tAtPut(const char* name, size_t len, size_t* value, Flag::Flags origin);
+ static Flag::Error size_tAtPut(const char* name, size_t* value, Flag::Flags origin) { return size_tAtPut(name, strlen(name), value, origin); }
- static bool uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked = false, bool return_flag = false);
- static bool uint64_tAt(const char* name, uint64_t* value, bool allow_locked = false, bool return_flag = false) { return uint64_tAt(name, strlen(name), value, allow_locked, return_flag); }
- static bool uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin);
- static bool uint64_tAtPut(const char* name, uint64_t* value, Flag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); }
+ static Flag::Error uint64_tAt(const char* name, size_t len, uint64_t* value, bool allow_locked = false, bool return_flag = false);
+ static Flag::Error uint64_tAt(const char* name, uint64_t* value, bool allow_locked = false, bool return_flag = false) { return uint64_tAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error uint64_tAtPut(const char* name, size_t len, uint64_t* value, Flag::Flags origin);
+ static Flag::Error uint64_tAtPut(const char* name, uint64_t* value, Flag::Flags origin) { return uint64_tAtPut(name, strlen(name), value, origin); }
- static bool doubleAt(const char* name, size_t len, double* value, bool allow_locked = false, bool return_flag = false);
- static bool doubleAt(const char* name, double* value, bool allow_locked = false, bool return_flag = false) { return doubleAt(name, strlen(name), value, allow_locked, return_flag); }
- static bool doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin);
- static bool doubleAtPut(const char* name, double* value, Flag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); }
+ static Flag::Error doubleAt(const char* name, size_t len, double* value, bool allow_locked = false, bool return_flag = false);
+ static Flag::Error doubleAt(const char* name, double* value, bool allow_locked = false, bool return_flag = false) { return doubleAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error doubleAtPut(const char* name, size_t len, double* value, Flag::Flags origin);
+ static Flag::Error doubleAtPut(const char* name, double* value, Flag::Flags origin) { return doubleAtPut(name, strlen(name), value, origin); }
- static bool ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked = false, bool return_flag = false);
- static bool ccstrAt(const char* name, ccstr* value, bool allow_locked = false, bool return_flag = false) { return ccstrAt(name, strlen(name), value, allow_locked, return_flag); }
+ static Flag::Error ccstrAt(const char* name, size_t len, ccstr* value, bool allow_locked = false, bool return_flag = false);
+ static Flag::Error ccstrAt(const char* name, ccstr* value, bool allow_locked = false, bool return_flag = false) { return ccstrAt(name, strlen(name), value, allow_locked, return_flag); }
// Contract: Flag will make private copy of the incoming value.
// Outgoing value is always malloc-ed, and caller MUST call free.
- static bool ccstrAtPut(const char* name, size_t len, ccstr* value, Flag::Flags origin);
- static bool ccstrAtPut(const char* name, ccstr* value, Flag::Flags origin) { return ccstrAtPut(name, strlen(name), value, origin); }
+ static Flag::Error ccstrAtPut(const char* name, size_t len, ccstr* value, Flag::Flags origin);
+ static Flag::Error ccstrAtPut(const char* name, ccstr* value, Flag::Flags origin) { return ccstrAtPut(name, strlen(name), value, origin); }
// Returns false if name is not a command line flag.
static bool wasSetOnCmdline(const char* name, bool* value);
static void printSetFlags(outputStream* out);
- static void printFlags(outputStream* out, bool withComments);
+ // printRanges will print out flags type, name and range values as expected by -XX:+PrintFlagsRanges
+ static void printFlags(outputStream* out, bool withComments, bool printRanges = false);
+
+ // Returns true if all flags have their final values set (ready for ranges and constraint check)
+ static bool finishedInitializing() { return _finished_initializing; }
+
+ // Check the final values of all flags for ranges and constraints
+ static bool check_all_ranges_and_constraints();
static void verify() PRODUCT_RETURN;
};
@@ -559,8 +604,15 @@
//
// Note that when there is a need to support develop flags to be writeable,
// it can be done in the same way as product_rw.
+//
+// range is a macro that will expand to min and max arguments for range
+// checking code if provided - see commandLineFlagRangeList.hpp
+//
+// constraint is a macro that will expand to custom function call
+// for constraint checking if provided - see commandLineFlagConstraintList.hpp
+//
-#define RUNTIME_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, manageable, product_rw, lp64_product) \
+#define RUNTIME_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct, manageable, product_rw, lp64_product, range, constraint) \
\
lp64_product(bool, UseCompressedOops, false, \
"Use 32-bit object references in 64-bit VM. " \
@@ -580,19 +632,22 @@
"Heap allocation steps through preferred address regions to find" \
" where it can allocate the heap. Number of steps to take per " \
"region.") \
+ range(1, max_uintx) \
\
diagnostic(bool, PrintCompressedOopsMode, false, \
"Print compressed oops base address and encoding mode") \
\
lp64_product(intx, ObjectAlignmentInBytes, 8, \
"Default object alignment in bytes, 8 is minimum") \
+ range(8, 256) \
+ constraint(ObjectAlignmentInBytesConstraintFunc) \
\
product(bool, AssumeMP, false, \
"Instruct the VM to assume multiple processors are available") \
\
- /* UseMembar is theoretically a temp flag used for memory barrier \
- * removal testing. It was supposed to be removed before FCS but has \
- * been re-added (see 6401008) */ \
+ /* UseMembar is theoretically a temp flag used for memory barrier */ \
+ /* removal testing. It was supposed to be removed before FCS but has */ \
+ /* been re-added (see 6401008) */ \
product_pd(bool, UseMembar, \
"(Unstable) Issues membars on thread state transitions") \
\
@@ -649,6 +704,7 @@
"Percentage (0-100) used to weight the current sample when " \
"computing exponentially decaying average for " \
"AdaptiveNUMAChunkSizing") \
+ range(0, 100) \
\
product(size_t, NUMASpaceResizeRate, 1*G, \
"Do not reallocate more than this amount per collection") \
@@ -841,7 +897,7 @@
"Die upon failure to reach safepoint (see SafepointTimeout)") \
\
/* 50 retries * (5 * current_retry_count) millis = ~6.375 seconds */ \
- /* typically, at most a few retries are needed */ \
+ /* typically, at most a few retries are needed */ \
product(intx, SuspendRetryCount, 50, \
"Maximum retry count for an external suspend request") \
\
@@ -862,6 +918,7 @@
\
diagnostic(uintx, LogEventsBufferEntries, 10, \
"Number of ring buffer event logs") \
+ range(1, NOT_LP64(1*K) LP64_ONLY(1*M)) \
\
product(bool, BytecodeVerificationRemote, true, \
"Enable the Java bytecode verifier for remote classes") \
@@ -1034,6 +1091,7 @@
"0: do not allow scavengable oops in the code cache; " \
"1: allow scavenging from the code cache; " \
"2: emit as many constants as the compiler can see") \
+ range(0, 2) \
\
product(bool, AlwaysRestoreFPU, false, \
"Restore the FPU control word after every JNI call (expensive)") \
@@ -1307,8 +1365,10 @@
"Use SSE2 MOVQ instruction for Arraycopy") \
\
product(intx, FieldsAllocationStyle, 1, \
- "0 - type based with oops first, 1 - with oops last, " \
+ "0 - type based with oops first, " \
+ "1 - with oops last, " \
"2 - oops in super and sub classes are together") \
+ range(0, 2) \
\
product(bool, CompactFields, true, \
"Allocate nonstatic fields in gaps between previous fields") \
@@ -1316,8 +1376,14 @@
notproduct(bool, PrintFieldLayout, false, \
"Print field layout for each class") \
\
+ /* Need to limit the extent of the padding to reasonable size. */\
+ /* 8K is well beyond the reasonable HW cache line size, even with */\
+ /* aggressive prefetching, while still leaving the room for segregating */\
+ /* among the distinct pages. */\
product(intx, ContendedPaddingWidth, 128, \
"How many bytes to pad the fields/classes marked @Contended with")\
+ range(0, 8192) \
+ constraint(ContendedPaddingWidthConstraintFunc) \
\
product(bool, EnableContended, true, \
"Enable @Contended annotation support") \
@@ -1365,7 +1431,7 @@
\
/* This option can change an EMCP method into an obsolete method. */ \
/* This can affect tests that except specific methods to be EMCP. */ \
- /* This option should be used with caution. */ \
+ /* This option should be used with caution. */ \
product(bool, StressLdcRewrite, false, \
"Force ldc -> ldc_w rewrite during RedefineClasses") \
\
@@ -1479,12 +1545,14 @@
product(uintx, ParallelOldDeadWoodLimiterMean, 50, \
"The mean used by the parallel compact dead wood " \
"limiter (a number between 0-100)") \
+ range(0, 100) \
\
product(uintx, ParallelOldDeadWoodLimiterStdDev, 80, \
"The standard deviation used by the parallel compact dead wood " \
"limiter (a number between 0-100)") \
- \
- product(uintx, ParallelGCThreads, 0, \
+ range(0, 100) \
+ \
+ product(uint, ParallelGCThreads, 0, \
"Number of parallel threads parallel gc will use") \
\
product(bool, UseDynamicNumberOfGCThreads, false, \
@@ -1498,6 +1566,7 @@
product(size_t, HeapSizePerGCThread, ScaleForWordSize(64*M), \
"Size of heap (bytes) per GC thread used in calculating the " \
"number of GC threads") \
+ range((uintx)os::vm_page_size(), max_uintx) \
\
product(bool, TraceDynamicGCThreads, false, \
"Trace the dynamic GC thread usage") \
@@ -1508,8 +1577,9 @@
\
develop(uintx, ParallelOldGCSplitInterval, 3, \
"How often to provoke splitting a young gen space") \
- \
- product(uintx, ConcGCThreads, 0, \
+ range(0, max_uintx) \
+ \
+ product(uint, ConcGCThreads, 0, \
"Number of threads concurrent gc will use") \
\
product(size_t, YoungPLABSize, 4096, \
@@ -1521,6 +1591,7 @@
\
product(uintx, GCTaskTimeStampEntries, 200, \
"Number of time stamp entries per gc worker thread") \
+ range(1, max_uintx) \
\
product(bool, AlwaysTenure, false, \
"Always tenure objects in eden (ParallelGC only)") \
@@ -1554,6 +1625,7 @@
product(uintx, GCLockerEdenExpansionPercent, 5, \
"How much the GC can expand the eden by while the GC locker " \
"is active (as a percentage)") \
+ range(0, 100) \
\
diagnostic(uintx, GCLockerRetryAllocationCount, 2, \
"Number of times to retry allocations when " \
@@ -1579,14 +1651,17 @@
\
product(uintx, ParallelGCBufferWastePct, 10, \
"Wasted fraction of parallel allocation buffer") \
+ range(0, 100) \
\
product(uintx, TargetPLABWastePct, 10, \
"Target wasted space in last buffer as percent of overall " \
"allocation") \
+ range(1, 100) \
\
product(uintx, PLABWeight, 75, \
"Percentage (0-100) used to weight the current sample when " \
"computing exponentially decaying average for ResizePLAB") \
+ range(0, 100) \
\
product(bool, ResizePLAB, true, \
"Dynamically resize (survivor space) promotion LAB's") \
@@ -1597,6 +1672,7 @@
product(intx, ParGCArrayScanChunk, 50, \
"Scan a subset of object array and push remainder, if array is " \
"bigger than this") \
+ range(1, max_intx) \
\
product(bool, ParGCUseLocalOverflow, false, \
"Instead of a global overflow list, use local overflow stacks") \
@@ -1618,15 +1694,18 @@
diagnostic(uintx, ParGCStridesPerThread, 2, \
"The number of strides per worker thread that we divide up the " \
"card table scanning work into") \
+ range(1, max_uintx) \
\
diagnostic(intx, ParGCCardsPerStrideChunk, 256, \
"The number of cards in each chunk of the parallel chunks used " \
"during card table scanning") \
+ range(1, max_intx) \
\
product(uintx, OldPLABWeight, 50, \
"Percentage (0-100) used to weight the current sample when " \
"computing exponentially decaying average for resizing " \
"OldPLABSize") \
+ range(0, 100) \
\
product(bool, ResizeOldPLAB, true, \
"Dynamically resize (old gen) promotion LAB's") \
@@ -1634,17 +1713,21 @@
product(bool, PrintOldPLAB, false, \
"Print (old gen) promotion LAB's sizing decisions") \
\
+ product(size_t, CMSOldPLABMax, 1024, \
+ "Maximum size of CMS gen promotion LAB caches per worker " \
+ "per block size") \
+ range(1, max_uintx) \
+ \
product(size_t, CMSOldPLABMin, 16, \
"Minimum size of CMS gen promotion LAB caches per worker " \
"per block size") \
- \
- product(size_t, CMSOldPLABMax, 1024, \
- "Maximum size of CMS gen promotion LAB caches per worker " \
- "per block size") \
+ range(1, max_uintx) \
+ constraint(CMSOldPLABMinConstraintFunc) \
\
product(uintx, CMSOldPLABNumRefills, 4, \
"Nominal number of refills of CMS gen promotion LAB cache " \
"per worker per block size") \
+ range(1, max_uintx) \
\
product(bool, CMSOldPLABResizeQuicker, false, \
"React on-the-fly during a scavenge to a sudden " \
@@ -1653,6 +1736,7 @@
product(uintx, CMSOldPLABToleranceFactor, 4, \
"The tolerance of the phase-change detector for on-the-fly " \
"PLAB resizing during a scavenge") \
+ range(1, max_uintx) \
\
product(uintx, CMSOldPLABReactivityFactor, 2, \
"The gain in the feedback loop for on-the-fly PLAB resizing " \
@@ -1664,19 +1748,23 @@
product_pd(size_t, CMSYoungGenPerWorker, \
"The maximum size of young gen chosen by default per GC worker " \
"thread available") \
+ range(1, max_uintx) \
\
product(uintx, CMSIncrementalSafetyFactor, 10, \
"Percentage (0-100) used to add conservatism when computing the " \
"duty cycle") \
+ range(0, 100) \
\
product(uintx, CMSExpAvgFactor, 50, \
"Percentage (0-100) used to weight the current sample when " \
"computing exponential averages for CMS statistics") \
+ range(0, 100) \
\
product(uintx, CMS_FLSWeight, 75, \
"Percentage (0-100) used to weight the current sample when " \
"computing exponentially decaying averages for CMS FLS " \
"statistics") \
+ range(0, 100) \
\
product(uintx, CMS_FLSPadding, 1, \
"The multiple of deviation from mean to use for buffering " \
@@ -1685,6 +1773,7 @@
product(uintx, FLSCoalescePolicy, 2, \
"CMS: aggressiveness level for coalescing, increasing " \
"from 0 to 4") \
+ range(0, 4) \
\
product(bool, FLSAlwaysCoalesceLarge, false, \
"CMS: larger free blocks are always available for coalescing") \
@@ -1718,6 +1807,7 @@
"Percentage (0-100) used to weight the current sample when " \
"computing exponentially decaying average for inter-sweep " \
"duration") \
+ range(0, 100) \
\
product(uintx, CMS_SweepPadding, 1, \
"The multiple of deviation from mean to use for buffering " \
@@ -1758,6 +1848,7 @@
\
product(size_t, MarkStackSizeMax, NOT_LP64(4*M) LP64_ONLY(512*M), \
"Maximum size of marking stack") \
+ range(1, (max_jint - 1)) \
\
notproduct(bool, CMSMarkStackOverflowALot, false, \
"Simulate frequent marking stack / work queue overflow") \
@@ -1781,9 +1872,11 @@
\
product(size_t, CMSRescanMultiple, 32, \
"Size (in cards) of CMS parallel rescan task") \
+ range(1, max_uintx) \
\
product(size_t, CMSConcMarkMultiple, 32, \
"Size (in cards) of CMS concurrent MT marking task") \
+ range(1, max_uintx) \
\
product(bool, CMSAbortSemantics, false, \
"Whether abort-on-overflow semantics is implemented") \
@@ -1819,14 +1912,19 @@
\
product(uintx, CMSPrecleanIter, 3, \
"Maximum number of precleaning iteration passes") \
+ range(0, 9) \
+ \
+ product(uintx, CMSPrecleanDenominator, 3, \
+ "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \
+ "ratio") \
+ range(1, max_uintx) \
+ constraint(CMSPrecleanDenominatorConstraintFunc) \
\
product(uintx, CMSPrecleanNumerator, 2, \
"CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \
"ratio") \
- \
- product(uintx, CMSPrecleanDenominator, 3, \
- "CMSPrecleanNumerator:CMSPrecleanDenominator yields convergence " \
- "ratio") \
+ range(0, max_uintx-1) \
+ constraint(CMSPrecleanNumeratorConstraintFunc) \
\
product(bool, CMSPrecleanRefLists1, true, \
"Preclean ref lists during (initial) preclean phase") \
@@ -1842,12 +1940,14 @@
\
product(uintx, CMSPrecleanThreshold, 1000, \
"Do not iterate again if number of dirty cards is less than this")\
+ range(100, max_uintx) \
\
product(bool, CMSCleanOnEnter, true, \
"Clean-on-enter optimization for reducing number of dirty cards") \
\
product(uintx, CMSRemarkVerifyVariant, 1, \
"Choose variant (1,2) of verification following remark") \
+ range(1, 2) \
\
product(size_t, CMSScheduleRemarkEdenSizeThreshold, 2*M, \
"If Eden size is below this, do not try to schedule remark") \
@@ -1855,14 +1955,17 @@
product(uintx, CMSScheduleRemarkEdenPenetration, 50, \
"The Eden occupancy percentage (0-100) at which " \
"to try and schedule remark pause") \
+ range(0, 100) \
\
product(uintx, CMSScheduleRemarkSamplingRatio, 5, \
"Start sampling eden top at least before young gen " \
"occupancy reaches 1/<ratio> of the size at which " \
"we plan to schedule remark") \
+ range(1, max_uintx) \
\
product(uintx, CMSSamplingGrain, 16*K, \
"The minimum distance between eden samples for CMS (see above)") \
+ range(1, max_uintx) \
\
product(bool, CMSScavengeBeforeRemark, false, \
"Attempt scavenge before the CMS remark step") \
@@ -1886,6 +1989,7 @@
product(size_t, CMSBitMapYieldQuantum, 10*M, \
"Bitmap operations should process at most this many bits " \
"between yields") \
+ range(1, max_uintx) \
\
product(bool, CMSDumpAtPromotionFailure, false, \
"Dump useful information about the state of the CMS old " \
@@ -1925,6 +2029,8 @@
product(intx, RefDiscoveryPolicy, 0, \
"Select type of reference discovery policy: " \
"reference-based(0) or referent-based(1)") \
+ range(ReferenceProcessor::DiscoveryPolicyMin, \
+ ReferenceProcessor::DiscoveryPolicyMax) \
\
product(bool, ParallelRefProcEnabled, false, \
"Enable parallel reference processing whenever possible") \
@@ -1935,14 +2041,17 @@
product(uintx, CMSTriggerRatio, 80, \
"Percentage of MinHeapFreeRatio in CMS generation that is " \
"allocated before a CMS collection cycle commences") \
+ range(0, 100) \
\
product(uintx, CMSBootstrapOccupancy, 50, \
"Percentage CMS generation occupancy at which to " \
"initiate CMS collection for bootstrapping collection stats") \
+ range(0, 100) \
\
product(intx, CMSInitiatingOccupancyFraction, -1, \
"Percentage CMS generation occupancy to start a CMS collection " \
"cycle. A negative value means that CMSTriggerRatio is used") \
+ range(min_intx, 100) \
\
product(uintx, InitiatingHeapOccupancyPercent, 45, \
"Percentage of the (entire) heap occupancy to start a " \
@@ -1950,10 +2059,12 @@
"concurrent GC cycle based on the occupancy of the entire heap, " \
"not just one of the generations (e.g., G1). A value of 0 " \
"denotes 'do constant GC cycles'.") \
+ range(0, 100) \
\
manageable(intx, CMSTriggerInterval, -1, \
"Commence a CMS collection cycle (at least) every so many " \
"milliseconds (0 permanently, -1 disabled)") \
+ range(-1, max_intx) \
\
product(bool, UseCMSInitiatingOccupancyOnly, false, \
"Only use occupancy as a criterion for starting a CMS collection")\
@@ -1961,6 +2072,7 @@
product(uintx, CMSIsTooFullPercentage, 98, \
"An absolute ceiling above which CMS will always consider the " \
"unloading of classes when class unloading is enabled") \
+ range(0, 100) \
\
develop(bool, CMSTestInFreeList, false, \
"Check if the coalesced range is already in the " \
@@ -2070,17 +2182,21 @@
product(uintx, MaxRAMFraction, 4, \
"Maximum fraction (1/n) of real memory used for maximum heap " \
"size") \
+ range(1, max_uintx) \
\
product(uintx, DefaultMaxRAMFraction, 4, \
"Maximum fraction (1/n) of real memory used for maximum heap " \
"size; deprecated: to be renamed to MaxRAMFraction") \
+ range(1, max_uintx) \
\
product(uintx, MinRAMFraction, 2, \
"Minimum fraction (1/n) of real memory used for maximum heap " \
"size on systems with small physical memory size") \
+ range(1, max_uintx) \
\
product(uintx, InitialRAMFraction, 64, \
"Fraction (1/n) of real memory used for initial heap size") \
+ range(1, max_uintx) \
\
develop(uintx, MaxVirtMemFraction, 2, \
"Maximum fraction (1/n) of virtual memory used for ergonomically "\
@@ -2139,9 +2255,11 @@
\
product(uintx, AdaptiveSizePolicyWeight, 10, \
"Weight given to exponential resizing, between 0 and 100") \
+ range(0, 100) \
\
product(uintx, AdaptiveTimeWeight, 25, \
"Weight given to time in adaptive policy, between 0 and 100") \
+ range(0, 100) \
\
product(uintx, PausePadding, 1, \
"How much buffer to keep for pause time") \
@@ -2154,6 +2272,7 @@
\
product(uintx, ThresholdTolerance, 10, \
"Allowed collection cost difference between generations") \
+ range(0, 100) \
\
product(uintx, AdaptiveSizePolicyCollectionCostMargin, 50, \
"If collection costs are within margin, reduce both by full " \
@@ -2161,21 +2280,27 @@
\
product(uintx, YoungGenerationSizeIncrement, 20, \
"Adaptive size percentage change in young generation") \
+ range(0, 100) \
\
product(uintx, YoungGenerationSizeSupplement, 80, \
"Supplement to YoungedGenerationSizeIncrement used at startup") \
+ range(0, 100) \
\
product(uintx, YoungGenerationSizeSupplementDecay, 8, \
"Decay factor to YoungedGenerationSizeSupplement") \
+ range(1, max_uintx) \
\
product(uintx, TenuredGenerationSizeIncrement, 20, \
"Adaptive size percentage change in tenured generation") \
+ range(0, 100) \
\
product(uintx, TenuredGenerationSizeSupplement, 80, \
"Supplement to TenuredGenerationSizeIncrement used at startup") \
+ range(0, 100) \
\
product(uintx, TenuredGenerationSizeSupplementDecay, 2, \
"Decay factor to TenuredGenerationSizeIncrement") \
+ range(1, max_uintx) \
\
product(uintx, MaxGCPauseMillis, max_uintx, \
"Adaptive size policy maximum GC pause time goal in millisecond, "\
@@ -2193,6 +2318,7 @@
\
product(uintx, AdaptiveSizeDecrementScaleFactor, 4, \
"Adaptive size scale down factor for shrinking") \
+ range(1, max_uintx) \
\
product(bool, UseAdaptiveSizeDecayMajorGCCost, true, \
"Adaptive size decays the major cost for long major intervals") \
@@ -2216,10 +2342,12 @@
product(uintx, GCTimeLimit, 98, \
"Limit of the proportion of time spent in GC before " \
"an OutOfMemoryError is thrown (used with GCHeapFreeLimit)") \
+ range(0, 100) \
\
product(uintx, GCHeapFreeLimit, 2, \
"Minimum percentage of free space after a full GC before an " \
"OutOfMemoryError is thrown (used with GCTimeLimit)") \
+ range(0, 100) \
\
develop(uintx, AdaptiveSizePolicyGCTimeLimitThreshold, 5, \
"Number of consecutive collections before gc time limit fires") \
@@ -2504,11 +2632,16 @@
\
/* compiler */ \
\
+ /* notice: the max range value here is max_jint, not max_intx */ \
+ /* because of overflow issue */ \
product(intx, CICompilerCount, CI_COMPILER_COUNT, \
"Number of compiler threads to run") \
+ range((intx)Arguments::get_min_number_of_compiler_threads(), \
+ max_jint) \
\
product(intx, CompilationPolicyChoice, 0, \
"which compilation policy (0-3)") \
+ range(0, 3) \
\
develop(bool, UseStackBanging, true, \
"use stack banging for stack overflow checks (required for " \
@@ -2625,6 +2758,9 @@
"Print all VM flags with default values and descriptions and " \
"exit") \
\
+ product(bool, PrintFlagsRanges, false, \
+ "Print VM flags and their ranges and exit VM") \
+ \
diagnostic(bool, SerializeVMOutput, true, \
"Use a mutex to serialize output to tty and LogFile") \
\
@@ -2863,6 +2999,7 @@
product(intx, ProfileMaturityPercentage, 20, \
"number of method invocations/branches (expressed as % of " \
"CompileThreshold) before using the method's profile") \
+ range(0, 100) \
\
diagnostic(bool, PrintMethodData, false, \
"Print the results of +ProfileInterpreter at end of run") \
@@ -2923,6 +3060,7 @@
"1 = prefetch instructions for each allocation, " \
"2 = use TLAB watermark to gate allocation prefetch, " \
"3 = use BIS instruction on Sparc for allocation prefetch") \
+ range(0, 3) \
\
product(intx, AllocatePrefetchDistance, -1, \
"Distance to prefetch ahead of allocation pointer") \
@@ -2969,6 +3107,7 @@
product(intx, NmethodSweepActivity, 10, \
"Removes cold nmethods from code cache if > 0. Higher values " \
"result in more aggressive sweeping") \
+ range(0, 2000) \
\
notproduct(bool, LogSweeper, false, \
"Keep a ring buffer of sweeper activity") \
@@ -3097,15 +3236,18 @@
\
product(intx, PerMethodRecompilationCutoff, 400, \
"After recompiling N times, stay in the interpreter (-1=>'Inf')") \
+ range(-1, max_intx) \
\
product(intx, PerBytecodeRecompilationCutoff, 200, \
"Per-BCI limit on repeated recompilation (-1=>'Inf')") \
+ range(-1, max_intx) \
\
product(intx, PerMethodTrapLimit, 100, \
"Limit on traps (of one kind) in a method (includes inlines)") \
\
experimental(intx, PerMethodSpecTrapLimit, 5000, \
- "Limit on speculative traps (of one kind) in a method (includes inlines)") \
+ "Limit on speculative traps (of one kind) in a method " \
+ "(includes inlines)") \
\
product(intx, PerBytecodeTrapLimit, 4, \
"Limit on traps (of one kind) at a particular BCI") \
@@ -3158,15 +3300,21 @@
\
product(size_t, MinTLABSize, 2*K, \
"Minimum allowed TLAB size (in bytes)") \
+ range(1, max_uintx) \
\
product(uintx, TLABAllocationWeight, 35, \
"Allocation averaging weight") \
- \
+ range(0, 100) \
+ \
+ /* Limit the lower bound of this flag to 1 as it is used */ \
+ /* in a division expression. */ \
product(uintx, TLABWasteTargetPercent, 1, \
"Percentage of Eden that can be wasted") \
+ range(1, 100) \
\
product(uintx, TLABRefillWasteFraction, 64, \
"Maximum TLAB waste at a refill (internal fragmentation)") \
+ range(1, max_uintx) \
\
product(uintx, TLABWasteIncrement, 4, \
"Increment allowed waste at slow allocation") \
@@ -3190,16 +3338,21 @@
product(size_t, CompressedClassSpaceSize, 1*G, \
"Maximum size of class area in Metaspace when compressed " \
"class pointers are used") \
+ range(1*M, 3*G) \
\
manageable(uintx, MinHeapFreeRatio, 40, \
"The minimum percentage of heap free after GC to avoid expansion."\
" For most GCs this applies to the old generation. In G1 and" \
" ParallelGC it applies to the whole heap.") \
+ range(0, 100) \
+ constraint(MinHeapFreeRatioConstraintFunc) \
\
manageable(uintx, MaxHeapFreeRatio, 70, \
"The maximum percentage of heap free after GC to avoid shrinking."\
" For most GCs this applies to the old generation. In G1 and" \
" ParallelGC it applies to the whole heap.") \
+ range(0, 100) \
+ constraint(MaxHeapFreeRatioConstraintFunc) \
\
product(intx, SoftRefLRUPolicyMSPerMB, 1000, \
"Number of milliseconds per MB of free space in the heap") \
@@ -3210,13 +3363,17 @@
product(size_t, MinMetaspaceExpansion, ScaleForWordSize(256*K), \
"The minimum expansion of Metaspace (in bytes)") \
\
+ product(uintx, MaxMetaspaceFreeRatio, 70, \
+ "The maximum percentage of Metaspace free after GC to avoid " \
+ "shrinking") \
+ range(0, 100) \
+ constraint(MaxMetaspaceFreeRatioConstraintFunc) \
+ \
product(uintx, MinMetaspaceFreeRatio, 40, \
"The minimum percentage of Metaspace free after GC to avoid " \
"expansion") \
- \
- product(uintx, MaxMetaspaceFreeRatio, 70, \
- "The maximum percentage of Metaspace free after GC to avoid " \
- "shrinking") \
+ range(0, 99) \
+ constraint(MinMetaspaceFreeRatioConstraintFunc) \
\
product(size_t, MaxMetaspaceExpansion, ScaleForWordSize(4*M), \
"The maximum expansion of Metaspace without full GC (in bytes)") \
@@ -3233,12 +3390,17 @@
\
product(uintx, MaxTenuringThreshold, 15, \
"Maximum value for tenuring threshold") \
+ range(0, markOopDesc::max_age + 1) \
+ constraint(MaxTenuringThresholdConstraintFunc) \
\
product(uintx, InitialTenuringThreshold, 7, \
"Initial value for tenuring threshold") \
+ range(0, markOopDesc::max_age + 1) \
+ constraint(InitialTenuringThresholdConstraintFunc) \
\
product(uintx, TargetSurvivorRatio, 50, \
"Desired percentage of survivor space used after scavenge") \
+ range(0, 100) \
\
product(uintx, MarkSweepDeadRatio, 5, \
"Percentage (0-100) of the old gen allowed as dead wood. " \
@@ -3249,10 +3411,12 @@
"generation and treats this as the maximum value when the heap " \
"is either completely full or completely empty. Par compact " \
"also has a smaller default value; see arguments.cpp.") \
+ range(0, 100) \
\
product(uintx, MarkSweepAlwaysCompactCount, 4, \
"How often should we fully compact the heap (ignoring the dead " \
"space parameters)") \
+ range(1, max_uintx) \
\
product(intx, PrintCMSStatistics, 0, \
"Statistics for CMS") \
@@ -3292,13 +3456,17 @@
/* stack parameters */ \
product_pd(intx, StackYellowPages, \
"Number of yellow zone (recoverable overflows) pages") \
+ range(1, max_intx) \
\
product_pd(intx, StackRedPages, \
"Number of red zone (unrecoverable overflows) pages") \
- \
+ range(1, max_intx) \
+ \
+ /* greater stack shadow pages can't generate instruction to bang stack */ \
product_pd(intx, StackShadowPages, \
"Number of shadow zone (for overflow checking) pages " \
"this should exceed the depth of the VM and native call stack") \
+ range(1, 50) \
\
product_pd(intx, ThreadStackSize, \
"Thread Stack Size (in Kbytes)") \
@@ -3312,16 +3480,12 @@
develop_pd(size_t, JVMInvokeMethodSlack, \
"Stack space (bytes) required for JVM_InvokeMethod to complete") \
\
- product(size_t, ThreadSafetyMargin, 50*M, \
- "Thread safety margin is used on fixed-stack LinuxThreads (on " \
- "Linux/x86 only) to prevent heap-stack collision. Set to 0 to " \
- "disable this feature") \
- \
- /* code cache parameters */ \
+ /* code cache parameters */ \
/* ppc64/tiered compilation has large code-entry alignment. */ \
develop(uintx, CodeCacheSegmentSize, 64 PPC64_ONLY(+64) NOT_PPC64(TIERED_ONLY(+64)),\
"Code cache segment size (in bytes) - smallest unit of " \
"allocation") \
+ range(1, 1024) \
\
develop_pd(intx, CodeEntryAlignment, \
"Code entry alignment for generated code (in bytes)") \
@@ -3355,6 +3519,7 @@
\
develop_pd(uintx, CodeCacheMinBlockLength, \
"Minimum number of segments in a code cache block") \
+ range(1, 100) \
\
notproduct(bool, ExitOnFullCodeCache, false, \
"Exit the VM if we fill the code cache") \
@@ -3366,6 +3531,7 @@
"Start aggressive sweeping if X[%] of the code cache is free." \
"Segmented code cache: X[%] of the non-profiled heap." \
"Non-segmented code cache: X[%] of the total code cache") \
+ range(0, 100) \
\
/* interpreter debugging */ \
develop(intx, BinarySwitchThreshold, 5, \
@@ -3426,6 +3592,7 @@
"2 - treat class initializers for application classes as empty; " \
"3 - allow all class initializers to run during bootstrap but " \
" pretend they are empty after starting replay") \
+ range(0, 3) \
\
develop(bool, ReplayIgnoreInitErrors, false, \
"Ignore exceptions thrown during initialization for replay") \
@@ -3470,6 +3637,7 @@
" used with care, as sometimes it can cause performance "\
" degradation in the application and/or the entire system. On "\
" Linux this policy requires root privilege.") \
+ range(0, 1) \
\
product(bool, ThreadPriorityVerbose, false, \
"Print priority changes") \
@@ -3653,6 +3821,7 @@
product(uintx, IncreaseFirstTierCompileThresholdAt, 50, \
"Increase the compile threshold for C1 compilation if the code " \
"cache is filled by the specified percentage") \
+ range(0, 99) \
\
product(intx, TieredRateUpdateMinTime, 1, \
"Minimum rate sampling interval (in milliseconds)") \
@@ -3673,6 +3842,7 @@
product(intx, InterpreterProfilePercentage, 33, \
"NON_TIERED number of method invocations/branches (expressed as " \
"% of CompileThreshold) before profiling in the interpreter") \
+ range(0, 100) \
\
develop(intx, MaxRecompilationSearchLength, 10, \
"The maximum number of frames to inspect when searching for " \
@@ -3752,6 +3922,7 @@
product(intx, UnguardOnExecutionViolation, 0, \
"Unguard page and retry on no-execute fault (Win32 only) " \
"0=off, 1=conservative, 2=aggressive") \
+ range(0, 2) \
\
/* Serviceability Support */ \
\
@@ -3872,9 +4043,11 @@
\
product(uintx, StringTableSize, defaultStringTableSize, \
"Number of buckets in the interned String table") \
+ range(minimumStringTableSize, 111*defaultStringTableSize) \
\
experimental(uintx, SymbolTableSize, defaultSymbolTableSize, \
"Number of buckets in the JVM internal Symbol table") \
+ range(minimumSymbolTableSize, 111*defaultSymbolTableSize) \
\
product(bool, UseStringDeduplication, false, \
"Use string deduplication") \
@@ -3885,6 +4058,7 @@
product(uintx, StringDeduplicationAgeThreshold, 3, \
"A string must reach this age (or be promoted to an old region) " \
"to be considered for deduplication") \
+ range(1, markOopDesc::max_age) \
\
diagnostic(bool, StringDeduplicationResizeALot, false, \
"Force table resize every time the table is scanned") \
@@ -3906,6 +4080,7 @@
\
experimental(intx, SurvivorAlignmentInBytes, 0, \
"Default survivor space alignment in bytes") \
+ constraint(SurvivorAlignmentInBytesConstraintFunc) \
\
product(bool , AllowNonVirtualCalls, false, \
"Obey the ACC_SUPER flag and allow invokenonvirtual calls") \
@@ -3963,7 +4138,7 @@
#define DECLARE_DEVELOPER_FLAG(type, name, value, doc) extern "C" type name;
#define DECLARE_PD_DEVELOPER_FLAG(type, name, doc) extern "C" type name;
#define DECLARE_NOTPRODUCT_FLAG(type, name, value, doc) extern "C" type name;
-#endif
+#endif // PRODUCT
// Special LP64 flags, product only needed for now.
#ifdef _LP64
#define DECLARE_LP64_PRODUCT_FLAG(type, name, value, doc) extern "C" type name;
@@ -3986,18 +4161,47 @@
#define MATERIALIZE_DEVELOPER_FLAG(type, name, value, doc) type name = value;
#define MATERIALIZE_PD_DEVELOPER_FLAG(type, name, doc) type name = pd_##name;
#define MATERIALIZE_NOTPRODUCT_FLAG(type, name, value, doc) type name = value;
-#endif
+#endif // PRODUCT
#ifdef _LP64
#define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) type name = value;
#else
#define MATERIALIZE_LP64_PRODUCT_FLAG(type, name, value, doc) /* flag is constant */
#endif // _LP64
-RUNTIME_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG, DECLARE_LP64_PRODUCT_FLAG)
+// Only materialize src code for range checking when required, ignore otherwise
+#define IGNORE_RANGE(a, b)
+// Only materialize src code for contraint checking when required, ignore otherwise
+#define IGNORE_CONSTRAINT(func)
-RUNTIME_OS_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG)
+RUNTIME_FLAGS(DECLARE_DEVELOPER_FLAG, \
+ DECLARE_PD_DEVELOPER_FLAG, \
+ DECLARE_PRODUCT_FLAG, \
+ DECLARE_PD_PRODUCT_FLAG, \
+ DECLARE_DIAGNOSTIC_FLAG, \
+ DECLARE_EXPERIMENTAL_FLAG, \
+ DECLARE_NOTPRODUCT_FLAG, \
+ DECLARE_MANAGEABLE_FLAG, \
+ DECLARE_PRODUCT_RW_FLAG, \
+ DECLARE_LP64_PRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
-ARCH_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG)
+RUNTIME_OS_FLAGS(DECLARE_DEVELOPER_FLAG, \
+ DECLARE_PD_DEVELOPER_FLAG, \
+ DECLARE_PRODUCT_FLAG, \
+ DECLARE_PD_PRODUCT_FLAG, \
+ DECLARE_DIAGNOSTIC_FLAG, \
+ DECLARE_NOTPRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
+
+ARCH_FLAGS(DECLARE_DEVELOPER_FLAG, \
+ DECLARE_PRODUCT_FLAG, \
+ DECLARE_DIAGNOSTIC_FLAG, \
+ DECLARE_EXPERIMENTAL_FLAG, \
+ DECLARE_NOTPRODUCT_FLAG, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
// Extensions
--- a/hotspot/src/share/vm/runtime/globals_extension.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/globals_extension.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -72,18 +72,67 @@
#define ARCH_NOTPRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name),
typedef enum {
- RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_EXPERIMENTAL_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER, RUNTIME_MANAGEABLE_FLAG_MEMBER, RUNTIME_PRODUCT_RW_FLAG_MEMBER, RUNTIME_LP64_PRODUCT_FLAG_MEMBER)
- RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER)
+ RUNTIME_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, \
+ RUNTIME_PD_DEVELOP_FLAG_MEMBER, \
+ RUNTIME_PRODUCT_FLAG_MEMBER, \
+ RUNTIME_PD_PRODUCT_FLAG_MEMBER, \
+ RUNTIME_DIAGNOSTIC_FLAG_MEMBER, \
+ RUNTIME_EXPERIMENTAL_FLAG_MEMBER, \
+ RUNTIME_NOTPRODUCT_FLAG_MEMBER, \
+ RUNTIME_MANAGEABLE_FLAG_MEMBER, \
+ RUNTIME_PRODUCT_RW_FLAG_MEMBER, \
+ RUNTIME_LP64_PRODUCT_FLAG_MEMBER, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
+ RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, \
+ RUNTIME_PD_DEVELOP_FLAG_MEMBER, \
+ RUNTIME_PRODUCT_FLAG_MEMBER, \
+ RUNTIME_PD_PRODUCT_FLAG_MEMBER, \
+ RUNTIME_DIAGNOSTIC_FLAG_MEMBER, \
+ RUNTIME_NOTPRODUCT_FLAG_MEMBER, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
#if INCLUDE_ALL_GCS
- G1_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, RUNTIME_PD_DEVELOP_FLAG_MEMBER, RUNTIME_PRODUCT_FLAG_MEMBER, RUNTIME_PD_PRODUCT_FLAG_MEMBER, RUNTIME_DIAGNOSTIC_FLAG_MEMBER, RUNTIME_EXPERIMENTAL_FLAG_MEMBER, RUNTIME_NOTPRODUCT_FLAG_MEMBER, RUNTIME_MANAGEABLE_FLAG_MEMBER, RUNTIME_PRODUCT_RW_FLAG_MEMBER)
+ G1_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER, \
+ RUNTIME_PD_DEVELOP_FLAG_MEMBER, \
+ RUNTIME_PRODUCT_FLAG_MEMBER, \
+ RUNTIME_PD_PRODUCT_FLAG_MEMBER, \
+ RUNTIME_DIAGNOSTIC_FLAG_MEMBER, \
+ RUNTIME_EXPERIMENTAL_FLAG_MEMBER, \
+ RUNTIME_NOTPRODUCT_FLAG_MEMBER, \
+ RUNTIME_MANAGEABLE_FLAG_MEMBER, \
+ RUNTIME_PRODUCT_RW_FLAG_MEMBER, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
#endif // INCLUDE_ALL_GCS
#ifdef COMPILER1
- C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_DIAGNOSTIC_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER)
+ C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, \
+ C1_PD_DEVELOP_FLAG_MEMBER, \
+ C1_PRODUCT_FLAG_MEMBER, \
+ C1_PD_PRODUCT_FLAG_MEMBER, \
+ C1_DIAGNOSTIC_FLAG_MEMBER, \
+ C1_NOTPRODUCT_FLAG_MEMBER, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
#endif
#ifdef COMPILER2
- C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, C2_PD_DEVELOP_FLAG_MEMBER, C2_PRODUCT_FLAG_MEMBER, C2_PD_PRODUCT_FLAG_MEMBER, C2_DIAGNOSTIC_FLAG_MEMBER, C2_EXPERIMENTAL_FLAG_MEMBER, C2_NOTPRODUCT_FLAG_MEMBER)
+ C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, \
+ C2_PD_DEVELOP_FLAG_MEMBER, \
+ C2_PRODUCT_FLAG_MEMBER, \
+ C2_PD_PRODUCT_FLAG_MEMBER, \
+ C2_DIAGNOSTIC_FLAG_MEMBER, \
+ C2_EXPERIMENTAL_FLAG_MEMBER, \
+ C2_NOTPRODUCT_FLAG_MEMBER, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
#endif
- ARCH_FLAGS(ARCH_DEVELOP_FLAG_MEMBER, ARCH_PRODUCT_FLAG_MEMBER, ARCH_DIAGNOSTIC_FLAG_MEMBER, ARCH_EXPERIMENTAL_FLAG_MEMBER, ARCH_NOTPRODUCT_FLAG_MEMBER)
+ ARCH_FLAGS(ARCH_DEVELOP_FLAG_MEMBER, \
+ ARCH_PRODUCT_FLAG_MEMBER, \
+ ARCH_DIAGNOSTIC_FLAG_MEMBER, \
+ ARCH_EXPERIMENTAL_FLAG_MEMBER, \
+ ARCH_NOTPRODUCT_FLAG_MEMBER, \
+ IGNORE_RANGE, \
+ IGNORE_CONSTRAINT)
COMMANDLINEFLAG_EXT
NUM_CommandLineFlag
} CommandLineFlag;
@@ -139,13 +188,17 @@
RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE,
RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE)
+ RUNTIME_LP64_PRODUCT_FLAG_MEMBER_WITH_TYPE,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT)
RUNTIME_OS_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE,
RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
RUNTIME_PRODUCT_FLAG_MEMBER_WITH_TYPE,
RUNTIME_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
RUNTIME_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE)
+ RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT)
#if INCLUDE_ALL_GCS
G1_FLAGS(RUNTIME_DEVELOP_FLAG_MEMBER_WITH_TYPE,
RUNTIME_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE,
@@ -155,7 +208,9 @@
RUNTIME_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
RUNTIME_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
RUNTIME_MANAGEABLE_FLAG_MEMBER_WITH_TYPE,
- RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE)
+ RUNTIME_PRODUCT_RW_FLAG_MEMBER_WITH_TYPE,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT)
#endif // INCLUDE_ALL_GCS
#ifdef COMPILER1
C1_FLAGS(C1_DEVELOP_FLAG_MEMBER_WITH_TYPE,
@@ -163,7 +218,9 @@
C1_PRODUCT_FLAG_MEMBER_WITH_TYPE,
C1_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
C1_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
- C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE)
+ C1_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT)
#endif
#ifdef COMPILER2
C2_FLAGS(C2_DEVELOP_FLAG_MEMBER_WITH_TYPE,
@@ -172,13 +229,17 @@
C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE,
C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
- C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE)
+ C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT)
#endif
ARCH_FLAGS(ARCH_DEVELOP_FLAG_MEMBER_WITH_TYPE,
ARCH_PRODUCT_FLAG_MEMBER_WITH_TYPE,
ARCH_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE,
ARCH_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE,
- ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE)
+ ARCH_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE,
+ IGNORE_RANGE,
+ IGNORE_CONSTRAINT)
COMMANDLINEFLAGWITHTYPE_EXT
NUM_CommandLineFlagWithType
} CommandLineFlagWithType;
@@ -196,16 +257,16 @@
// of a circular dependency on the enum definition.
class CommandLineFlagsEx : CommandLineFlags {
public:
- static void boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin);
- static void intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin);
- static void uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin);
- static void intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin);
- static void uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin);
- static void uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin);
- static void size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin);
- static void doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin);
+ static Flag::Error boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin);
+ static Flag::Error intAtPut(CommandLineFlagWithType flag, int value, Flag::Flags origin);
+ static Flag::Error uintAtPut(CommandLineFlagWithType flag, uint value, Flag::Flags origin);
+ static Flag::Error intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin);
+ static Flag::Error uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin);
+ static Flag::Error uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin);
+ static Flag::Error size_tAtPut(CommandLineFlagWithType flag, size_t value, Flag::Flags origin);
+ static Flag::Error doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin);
// Contract: Flag will make private copy of the incoming value
- static void ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin);
+ static Flag::Error ccstrAtPut(CommandLineFlagWithType flag, ccstr value, Flag::Flags origin);
static bool is_default(CommandLineFlag flag);
static bool is_ergo(CommandLineFlag flag);
--- a/hotspot/src/share/vm/runtime/init.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/init.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -29,6 +29,7 @@
#include "interpreter/bytecodes.hpp"
#include "memory/universe.hpp"
#include "prims/methodHandles.hpp"
+#include "runtime/globals.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/init.hpp"
@@ -141,8 +142,8 @@
// All the flags that get adjusted by VM_Version_init and os::init_2
// have been set so dump the flags now.
- if (PrintFlagsFinal) {
- CommandLineFlags::printFlags(tty, false);
+ if (PrintFlagsFinal || PrintFlagsRanges) {
+ CommandLineFlags::printFlags(tty, false, PrintFlagsRanges);
}
return JNI_OK;
--- a/hotspot/src/share/vm/runtime/os.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/os.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -670,8 +670,8 @@
}
// always move the block
void* ptr = os::malloc(size, memflags, stack);
- if (PrintMalloc) {
- tty->print_cr("os::remalloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, memblock, ptr);
+ if (PrintMalloc && tty != NULL) {
+ tty->print_cr("os::realloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, memblock, ptr);
}
// Copy to new memory if malloc didn't fail
if ( ptr != NULL ) {
@@ -832,7 +832,7 @@
}
}
-void os::print_cpu_info(outputStream* st) {
+void os::print_cpu_info(outputStream* st, char* buf, size_t buflen) {
// cpu
st->print("CPU:");
st->print("total %d", os::processor_count());
@@ -840,10 +840,10 @@
// st->print("(active %d)", os::active_processor_count());
st->print(" %s", VM_Version::cpu_features());
st->cr();
- pd_print_cpu_info(st);
+ pd_print_cpu_info(st, buf, buflen);
}
-void os::print_date_and_time(outputStream *st) {
+void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
const int secs_per_day = 86400;
const int secs_per_hour = 3600;
const int secs_per_min = 60;
@@ -852,6 +852,12 @@
(void)time(&tloc);
st->print("time: %s", ctime(&tloc)); // ctime adds newline.
+ struct tm tz;
+ if (localtime_pd(&tloc, &tz) != NULL) {
+ ::strftime(buf, buflen, "%Z", &tz);
+ st->print_cr("timezone: %s", buf);
+ }
+
double t = os::elapsedTime();
// NOTE: It tends to crash after a SEGV if we want to printf("%f",...) in
// Linux. Must be a bug in glibc ? Workaround is to round "t" to int
--- a/hotspot/src/share/vm/runtime/os.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/os.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -539,7 +539,8 @@
// If function name is not found, buf[0] is set to '\0' and offset is
// set to -1 (if offset is non-NULL).
static bool dll_address_to_function_name(address addr, char* buf,
- int buflen, int* offset);
+ int buflen, int* offset,
+ bool demangle = true);
// Locate DLL/DSO. On success, full path of the library is copied to
// buf, and offset is optionally set to be the distance between addr
@@ -587,8 +588,8 @@
// Output format may be different on different platforms.
static void print_os_info(outputStream* st);
static void print_os_info_brief(outputStream* st);
- static void print_cpu_info(outputStream* st);
- static void pd_print_cpu_info(outputStream* st);
+ static void print_cpu_info(outputStream* st, char* buf, size_t buflen);
+ static void pd_print_cpu_info(outputStream* st, char* buf, size_t buflen);
static void print_memory_info(outputStream* st);
static void print_dll_info(outputStream* st);
static void print_environment_variables(outputStream* st, const char** env_list);
@@ -596,7 +597,7 @@
static void print_register_info(outputStream* st, void* context);
static void print_siginfo(outputStream* st, void* siginfo);
static void print_signal_handlers(outputStream* st, char* buf, size_t buflen);
- static void print_date_and_time(outputStream* st);
+ static void print_date_and_time(outputStream* st, char* buf, size_t buflen);
static void print_location(outputStream* st, intptr_t x, bool verbose = false);
static size_t lasterror(char *buf, size_t len);
--- a/hotspot/src/share/vm/runtime/os_ext.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/os_ext.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,10 @@
#ifndef SHARE_VM_RUNTIME_OS_EXT_HPP
#define SHARE_VM_RUNTIME_OS_EXT_HPP
- public:
+#define EMIT_RANGES_FOR_GLOBALS_EXT // NOP
+#define EMIT_CONSTRAINTS_FOR_GLOBALS_EXT // NOP
+
+public:
static void init_globals_ext() {} // Run from init_globals().
// See os.hpp/cpp and init.cpp.
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -732,6 +732,8 @@
if (StackTraceInThrowable) {
java_lang_Throwable::fill_in_stack_trace(exception);
}
+ // Increment counter for hs_err file reporting
+ Atomic::inc(&Exceptions::_stack_overflow_errors);
throw_and_post_jvmti_exception(thread, exception);
JRT_END
@@ -2333,15 +2335,6 @@
// and a single writer: this could be fixed if it becomes a
// problem).
- // Get the address of the ic_miss handlers before we grab the
- // AdapterHandlerLibrary_lock. This fixes bug 6236259 which
- // was caused by the initialization of the stubs happening
- // while we held the lock and then notifying jvmti while
- // holding it. This just forces the initialization to be a little
- // earlier.
- address ic_miss = SharedRuntime::get_ic_miss_stub();
- assert(ic_miss != NULL, "must have handler");
-
ResourceMark rm;
NOT_PRODUCT(int insts_size);
--- a/hotspot/src/share/vm/runtime/signature.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/signature.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -63,6 +63,8 @@
// Fingerprinter.
enum {
static_feature_size = 1,
+ is_static_bit = 1,
+
result_feature_size = 4,
result_feature_mask = 0xF,
parameter_feature_size = 4,
@@ -114,6 +116,15 @@
// Object types (begin indexes the first character of the entry, end indexes the first character after the entry)
virtual void do_object(int begin, int end) = 0;
virtual void do_array (int begin, int end) = 0;
+
+ static bool is_static(uint64_t fingerprint) {
+ assert(fingerprint != (uint64_t)CONST64(-1), "invalid fingerprint");
+ return fingerprint & is_static_bit;
+ }
+ static BasicType return_type(uint64_t fingerprint) {
+ assert(fingerprint != (uint64_t)CONST64(-1), "invalid fingerprint");
+ return (BasicType) ((fingerprint >> static_feature_size) & result_feature_mask);
+ }
};
--- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -96,7 +96,7 @@
toprint[toprint_len++] = cdesc;
if (cdesc == _first_stub) { saw_first = true; break; }
}
- assert(saw_first, "must get both first & last");
+ assert(toprint_len == 0 || saw_first, "must get both first & last");
// Print in reverse order:
qsort(toprint, toprint_len, sizeof(toprint[0]), compare_cdesc);
for (int i = 0; i < toprint_len; i++) {
--- a/hotspot/src/share/vm/runtime/sweeper.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -678,7 +678,7 @@
// ReservedCodeCacheSize
int reset_val = hotness_counter_reset_val();
int time_since_reset = reset_val - nm->hotness_counter();
- int code_blob_type = (CodeCache::get_code_blob_type(nm->comp_level()));
+ int code_blob_type = CodeCache::get_code_blob_type(nm);
double threshold = -reset_val + (CodeCache::reverse_free_ratio(code_blob_type) * NmethodSweepActivity);
// The less free space in the code cache we have - the bigger reverse_free_ratio() is.
// I.e., 'threshold' increases with lower available space in the code cache and a higher
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/synchronizer.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/vmSymbols.hpp"
+#include "memory/metaspaceShared.hpp"
#include "memory/padded.hpp"
#include "memory/resourceArea.hpp"
#include "oops/markOop.hpp"
@@ -638,11 +639,11 @@
// hashCode() is a heap mutator ...
// Relaxing assertion for bug 6320749.
- assert(Universe::verify_in_progress() ||
+ assert(Universe::verify_in_progress() || DumpSharedSpaces ||
!SafepointSynchronize::is_at_safepoint(), "invariant");
- assert(Universe::verify_in_progress() ||
+ assert(Universe::verify_in_progress() || DumpSharedSpaces ||
Self->is_Java_thread() , "invariant");
- assert(Universe::verify_in_progress() ||
+ assert(Universe::verify_in_progress() || DumpSharedSpaces ||
((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant");
ObjectMonitor* monitor = NULL;
--- a/hotspot/src/share/vm/runtime/thread.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -54,6 +54,7 @@
#include "runtime/deoptimization.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/frame.inline.hpp"
+#include "runtime/globals.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/java.hpp"
@@ -3273,6 +3274,9 @@
jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
extern void JDK_Version_init();
+ // Preinitialize version info.
+ VM_Version::early_initialize();
+
// Check version
if (!is_supported_jni_version(args->version)) return JNI_EVERSION;
@@ -3303,6 +3307,11 @@
jint ergo_result = Arguments::apply_ergo();
if (ergo_result != JNI_OK) return ergo_result;
+ // Final check of all arguments after ergonomics which may change values.
+ if (!CommandLineFlags::check_all_ranges_and_constraints()) {
+ return JNI_EINVAL;
+ }
+
if (PauseAtStartup) {
os::pause();
}
--- a/hotspot/src/share/vm/runtime/timer.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/timer.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -59,7 +59,7 @@
}
jlong elapsedTimer::milliseconds() const {
- return TimeHelper::counter_to_millis(_counter);
+ return (jlong)TimeHelper::counter_to_millis(_counter);
}
jlong elapsedTimer::active_ticks() const {
@@ -89,7 +89,7 @@
jlong TimeStamp::milliseconds() const {
assert(is_updated(), "must not be clear");
jlong new_count = os::elapsed_counter();
- return TimeHelper::counter_to_millis(new_count - _counter);
+ return (jlong)TimeHelper::counter_to_millis(new_count - _counter);
}
jlong TimeStamp::ticks_since_update() const {
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -545,7 +545,6 @@
\
nonstatic_field(Generation, _reserved, MemRegion) \
nonstatic_field(Generation, _virtual_space, VirtualSpace) \
- nonstatic_field(Generation, _level, int) \
nonstatic_field(Generation, _stat_record, Generation::StatRecord) \
\
nonstatic_field(Generation::StatRecord, invocations, int) \
--- a/hotspot/src/share/vm/runtime/vm_version.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/vm_version.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -280,7 +280,8 @@
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
- os::print_cpu_info(tty);
+ char buf[512];
+ os::print_cpu_info(tty, buf, sizeof(buf));
}
#endif
}
--- a/hotspot/src/share/vm/runtime/vm_version.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/runtime/vm_version.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -58,6 +58,13 @@
public:
static void initialize();
+ // This allows for early initialization of VM_Version information
+ // that may be needed later in the initialization sequence but before
+ // full VM_Version initialization is possible. It can not depend on any
+ // other part of the VM being initialized when called. Platforms that
+ // need to specialize this define VM_Version::early_initialize().
+ static void early_initialize() { }
+
// Name
static const char* vm_name();
// Vendor
--- a/hotspot/src/share/vm/services/attachListener.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/services/attachListener.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -243,8 +243,8 @@
FormatBuffer<80> err_msg("%s", "");
int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), Flag::ATTACH_ON_DEMAND, err_msg);
- if (ret != WriteableFlags::SUCCESS) {
- if (ret == WriteableFlags::NON_WRITABLE) {
+ if (ret != Flag::SUCCESS) {
+ if (ret == Flag::NON_WRITABLE) {
// if the flag is not manageable try to change it through
// the platform dependent implementation
return AttachListener::pd_set_flag(op, out);
--- a/hotspot/src/share/vm/services/classLoadingService.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/services/classLoadingService.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
#include "services/memoryService.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/macros.hpp"
+#include "utilities/defaultStream.hpp"
#ifdef DTRACE_ENABLED
@@ -176,13 +177,12 @@
return class_size * oopSize;
}
-
bool ClassLoadingService::set_verbose(bool verbose) {
MutexLocker m(Management_lock);
// verbose will be set to the previous value
- bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassLoading", &verbose, Flag::MANAGEMENT);
- assert(succeed, "Setting TraceClassLoading flag fails");
+ Flag::Error error = CommandLineFlags::boolAtPut("TraceClassLoading", &verbose, Flag::MANAGEMENT);
+ assert(error==Flag::SUCCESS, err_msg("Setting TraceClassLoading flag failed with error %s", Flag::flag_error_str(error)));
reset_trace_class_unloading();
return verbose;
@@ -192,8 +192,8 @@
void ClassLoadingService::reset_trace_class_unloading() {
assert(Management_lock->owned_by_self(), "Must own the Management_lock");
bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose();
- bool succeed = CommandLineFlags::boolAtPut((char*)"TraceClassUnloading", &value, Flag::MANAGEMENT);
- assert(succeed, "Setting TraceClassUnLoading flag fails");
+ Flag::Error error = CommandLineFlags::boolAtPut("TraceClassUnloading", &value, Flag::MANAGEMENT);
+ assert(error==Flag::SUCCESS, err_msg("Setting TraceClassUnLoading flag failed with error %s", Flag::flag_error_str(error)));
}
GrowableArray<KlassHandle>* LoadedClassesEnumerator::_loaded_classes = NULL;
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -27,6 +27,7 @@
#include "classfile/compactHashtable.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "oops/oop.inline.hpp"
+#include "runtime/globals.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
#include "services/diagnosticArgument.hpp"
@@ -221,7 +222,7 @@
FormatBuffer<80> err_msg("%s", "");
int ret = WriteableFlags::set_flag(_flag.value(), val, Flag::MANAGEMENT, err_msg);
- if (ret != WriteableFlags::SUCCESS) {
+ if (ret != Flag::SUCCESS) {
output()->print_cr("%s", err_msg.buffer());
}
}
--- a/hotspot/src/share/vm/services/management.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/services/management.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1703,8 +1703,8 @@
FormatBuffer<80> err_msg("%s", "");
int succeed = WriteableFlags::set_flag(name, new_value, Flag::MANAGEMENT, err_msg);
- if (succeed != WriteableFlags::SUCCESS) {
- if (succeed == WriteableFlags::MISSING_VALUE) {
+ if (succeed != Flag::SUCCESS) {
+ if (succeed == Flag::MISSING_VALUE) {
// missing value causes NPE to be thrown
THROW(vmSymbols::java_lang_NullPointerException());
} else {
@@ -1713,7 +1713,7 @@
err_msg.buffer());
}
}
- assert(succeed == WriteableFlags::SUCCESS, "Setting flag should succeed");
+ assert(succeed == Flag::SUCCESS, "Setting flag should succeed");
JVM_END
class ThreadTimesClosure: public ThreadClosure {
--- a/hotspot/src/share/vm/services/memoryService.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/services/memoryService.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -127,7 +127,6 @@
assert(policy->is_generation_policy(), "Only support two generations");
GenCollectorPolicy* gen_policy = policy->as_generation_policy();
- guarantee(gen_policy->number_of_generations() == 2, "Only support two-generation heap");
if (gen_policy != NULL) {
Generation::Name kind = gen_policy->young_gen_spec()->name();
switch (kind) {
@@ -518,8 +517,8 @@
bool MemoryService::set_verbose(bool verbose) {
MutexLocker m(Management_lock);
// verbose will be set to the previous value
- bool succeed = CommandLineFlags::boolAtPut((char*)"PrintGC", &verbose, Flag::MANAGEMENT);
- assert(succeed, "Setting PrintGC flag fails");
+ Flag::Error error = CommandLineFlags::boolAtPut("PrintGC", &verbose, Flag::MANAGEMENT);
+ assert(error==Flag::SUCCESS, err_msg("Setting PrintGC flag failed with error %s", Flag::flag_error_str(error)));
ClassLoadingService::reset_trace_class_unloading();
return verbose;
--- a/hotspot/src/share/vm/services/virtualMemoryTracker.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/services/virtualMemoryTracker.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -347,6 +347,13 @@
return true;
}
+ // Mapped CDS string region.
+ // The string region(s) is part of the java heap.
+ if (reserved_rgn->flag() == mtJavaHeap) {
+ assert(reserved_rgn->contain_region(base_addr, size), "Reserved heap region should contain this mapping region");
+ return true;
+ }
+
ShouldNotReachHere();
return false;
}
--- a/hotspot/src/share/vm/services/writeableFlags.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/services/writeableFlags.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -25,129 +25,200 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "runtime/arguments.hpp"
+#include "runtime/commandLineFlagRangeList.hpp"
#include "runtime/java.hpp"
#include "runtime/jniHandles.hpp"
#include "services/writeableFlags.hpp"
+#define TEMP_BUF_SIZE 80
+
+static void buffer_concat(char* buffer, const char* src) {
+ strncat(buffer, src, TEMP_BUF_SIZE - 1 - strlen(buffer));
+}
+
+static void print_flag_error_message_bounds(const char* name, char* buffer) {
+ CommandLineFlagRange* range = CommandLineFlagRangeList::find(name);
+ if (range != NULL) {
+ buffer_concat(buffer, "must have value in range ");
+
+ stringStream stream;
+ range->print(&stream);
+ const char* range_string = stream.as_string();
+ size_t j = strlen(buffer);
+ for (size_t i=0; j<TEMP_BUF_SIZE-1; i++) {
+ if (range_string[i] == '\0') {
+ break;
+ } else if (range_string[i] != ' ') {
+ buffer[j] = range_string[i];
+ j++;
+ }
+ }
+ buffer[j] = '\0';
+ }
+}
+
+PRAGMA_FORMAT_NONLITERAL_IGNORED_EXTERNAL
+static void print_flag_error_message_if_needed(Flag::Error error, const char* name, FormatBuffer<80>& err_msg) {
+ if (error == Flag::SUCCESS) {
+ return;
+ }
+
+ char buffer[TEMP_BUF_SIZE] = {'\0'};
+ if ((error != Flag::MISSING_NAME) && (name != NULL)) {
+ buffer_concat(buffer, name);
+ buffer_concat(buffer, " error: ");
+ } else {
+ buffer_concat(buffer, "Error: ");
+ }
+ switch (error) {
+ case Flag::MISSING_NAME:
+ buffer_concat(buffer, "flag name is missing."); break;
+ case Flag::MISSING_VALUE:
+ buffer_concat(buffer, "parsing the textual form of the value."); break;
+ case Flag::NON_WRITABLE:
+ buffer_concat(buffer, "flag is not writeable."); break;
+ case Flag::OUT_OF_BOUNDS:
+ print_flag_error_message_bounds(name, buffer); break;
+ case Flag::VIOLATES_CONSTRAINT:
+ buffer_concat(buffer, "value violates its flag's constraint."); break;
+ case Flag::INVALID_FLAG:
+ buffer_concat(buffer, "there is no flag with the given name."); break;
+ case Flag::ERR_OTHER:
+ buffer_concat(buffer, "other, unspecified error related to setting the flag."); break;
+ case Flag::SUCCESS:
+ break;
+ }
+
+ PRAGMA_DIAG_PUSH
+ PRAGMA_FORMAT_NONLITERAL_IGNORED_INTERNAL
+ err_msg.print(buffer);
+ PRAGMA_DIAG_POP
+}
+
// set a boolean global flag
-int WriteableFlags::set_bool_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
int value = true;
if (sscanf(arg, "%d", &value)) {
return set_bool_flag(name, value != 0, origin, err_msg);
}
err_msg.print("flag value must be a boolean (1 or 0)");
- return WRONG_FORMAT;
+ return Flag::WRONG_FORMAT;
}
-int WriteableFlags::set_bool_flag(const char* name, bool value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
- return CommandLineFlags::boolAtPut((char*)name, &value, origin) ? SUCCESS : ERR_OTHER;
+Flag::Error WriteableFlags::set_bool_flag(const char* name, bool value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+ Flag::Error err = CommandLineFlags::boolAtPut(name, &value, origin);
+ print_flag_error_message_if_needed(err, name, err_msg);
+ return err;
}
// set a int global flag
-int WriteableFlags::set_int_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
int value;
if (sscanf(arg, "%d", &value)) {
return set_int_flag(name, value, origin, err_msg);
}
err_msg.print("flag value must be an integer");
- return WRONG_FORMAT;
+ return Flag::WRONG_FORMAT;
}
-int WriteableFlags::set_int_flag(const char* name, int value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
- return CommandLineFlags::intAtPut((char*)name, &value, origin) ? SUCCESS : ERR_OTHER;
+Flag::Error WriteableFlags::set_int_flag(const char* name, int value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+ Flag::Error err = CommandLineFlags::intAtPut(name, &value, origin);
+ print_flag_error_message_if_needed(err, name, err_msg);
+ return err;
}
// set a uint global flag
-int WriteableFlags::set_uint_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
uint value;
if (sscanf(arg, "%u", &value)) {
return set_uint_flag(name, value, origin, err_msg);
}
err_msg.print("flag value must be an unsigned integer");
- return WRONG_FORMAT;
+ return Flag::WRONG_FORMAT;
}
-int WriteableFlags::set_uint_flag(const char* name, uint value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
- return CommandLineFlags::uintAtPut((char*)name, &value, origin) ? SUCCESS : ERR_OTHER;
+Flag::Error WriteableFlags::set_uint_flag(const char* name, uint value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+ Flag::Error err = CommandLineFlags::uintAtPut(name, &value, origin);
+ print_flag_error_message_if_needed(err, name, err_msg);
+ return err;
}
// set a intx global flag
-int WriteableFlags::set_intx_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
intx value;
if (sscanf(arg, INTX_FORMAT, &value)) {
return set_intx_flag(name, value, origin, err_msg);
}
err_msg.print("flag value must be an integer");
- return WRONG_FORMAT;
+ return Flag::WRONG_FORMAT;
}
-int WriteableFlags::set_intx_flag(const char* name, intx value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
- return CommandLineFlags::intxAtPut((char*)name, &value, origin) ? SUCCESS : ERR_OTHER;
+Flag::Error WriteableFlags::set_intx_flag(const char* name, intx value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+ Flag::Error err = CommandLineFlags::intxAtPut(name, &value, origin);
+ print_flag_error_message_if_needed(err, name, err_msg);
+ return err;
}
// set a uintx global flag
-int WriteableFlags::set_uintx_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
uintx value;
if (sscanf(arg, UINTX_FORMAT, &value)) {
return set_uintx_flag(name, value, origin, err_msg);
}
err_msg.print("flag value must be an unsigned integer");
- return WRONG_FORMAT;
+ return Flag::WRONG_FORMAT;
}
-int WriteableFlags::set_uintx_flag(const char* name, uintx value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
- if (strncmp(name, "MaxHeapFreeRatio", 17) == 0) {
- if (!Arguments::verify_MaxHeapFreeRatio(err_msg, value)) {
- return OUT_OF_BOUNDS;
- }
- } else if (strncmp(name, "MinHeapFreeRatio", 17) == 0) {
- if (!Arguments::verify_MinHeapFreeRatio(err_msg, value)) {
- return OUT_OF_BOUNDS;
- }
- }
- return CommandLineFlags::uintxAtPut((char*)name, &value, origin) ? SUCCESS : ERR_OTHER;
+Flag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+ Flag::Error err = CommandLineFlags::uintxAtPut(name, &value, origin);
+ print_flag_error_message_if_needed(err, name, err_msg);
+ return err;
}
// set a uint64_t global flag
-int WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
uint64_t value;
if (sscanf(arg, UINT64_FORMAT, &value)) {
return set_uint64_t_flag(name, value, origin, err_msg);
}
err_msg.print("flag value must be an unsigned 64-bit integer");
- return WRONG_FORMAT;
+ return Flag::WRONG_FORMAT;
}
-int WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
- return CommandLineFlags::uint64_tAtPut((char*)name, &value, origin) ? SUCCESS : ERR_OTHER;
+Flag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+ Flag::Error err = CommandLineFlags::uint64_tAtPut(name, &value, origin);
+ print_flag_error_message_if_needed(err, name, err_msg);
+ return err;
}
// set a size_t global flag
-int WriteableFlags::set_size_t_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
size_t value;
if (sscanf(arg, SIZE_FORMAT, &value)) {
return set_size_t_flag(name, value, origin, err_msg);
}
err_msg.print("flag value must be an unsigned integer");
- return WRONG_FORMAT;
+ return Flag::WRONG_FORMAT;
}
-int WriteableFlags::set_size_t_flag(const char* name, size_t value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
- return CommandLineFlags::size_tAtPut((char*)name, &value, origin) ? SUCCESS : ERR_OTHER;
+Flag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+ Flag::Error err = CommandLineFlags::size_tAtPut(name, &value, origin);
+ print_flag_error_message_if_needed(err, name, err_msg);
+ return err;
}
// set a string global flag using value from AttachOperation
-int WriteableFlags::set_ccstr_flag(const char* name, const char* arg, Flag::Flags origin, FormatBuffer<80>& err_msg) {
- bool res = CommandLineFlags::ccstrAtPut((char*)name, &arg, origin);
-
- return res? SUCCESS : ERR_OTHER;
+Flag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+ Flag::Error err = CommandLineFlags::ccstrAtPut((char*)name, &value, origin);
+ print_flag_error_message_if_needed(err, name, err_msg);
+ return err;
}
/* sets a writeable flag to the provided value
@@ -155,7 +226,7 @@
* - return status is one of the WriteableFlags::err enum values
* - an eventual error message will be generated to the provided err_msg buffer
*/
-int WriteableFlags::set_flag(const char* flag_name, const char* flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
return set_flag(flag_name, &flag_value, set_flag_from_char, origin, err_msg);
}
@@ -164,19 +235,19 @@
* - return status is one of the WriteableFlags::err enum values
* - an eventual error message will be generated to the provided err_msg buffer
*/
-int WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
return set_flag(flag_name, &flag_value, set_flag_from_jvalue, origin, err_msg);
}
// a writeable flag setter accepting either 'jvalue' or 'char *' values
-int WriteableFlags::set_flag(const char* name, const void* value, int(*setter)(Flag*,const void*,Flag::Flags,FormatBuffer<80>&), Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_flag(const char* name, const void* value, Flag::Error(*setter)(Flag*,const void*,Flag::Flags,FormatBuffer<80>&), Flag::Flags origin, FormatBuffer<80>& err_msg) {
if (name == NULL) {
err_msg.print("flag name is missing");
- return MISSING_NAME;
+ return Flag::MISSING_NAME;
}
if (value == NULL) {
err_msg.print("flag value is missing");
- return MISSING_VALUE;
+ return Flag::MISSING_VALUE;
}
Flag* f = Flag::find_flag((char*)name, strlen(name));
@@ -186,20 +257,20 @@
return setter(f, value, origin, err_msg);
} else {
err_msg.print("only 'writeable' flags can be set");
- return NON_WRITABLE;
+ return Flag::NON_WRITABLE;
}
}
err_msg.print("flag %s does not exist", name);
- return INVALID_FLAG;
+ return Flag::INVALID_FLAG;
}
// a writeable flag setter accepting 'char *' values
-int WriteableFlags::set_flag_from_char(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_flag_from_char(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
char* flag_value = *(char**)value;
if (flag_value == NULL) {
err_msg.print("flag value is missing");
- return MISSING_VALUE;
+ return Flag::MISSING_VALUE;
}
if (f->is_bool()) {
return set_bool_flag(f->_name, flag_value, origin, err_msg);
@@ -220,11 +291,11 @@
} else {
ShouldNotReachHere();
}
- return ERR_OTHER;
+ return Flag::ERR_OTHER;
}
// a writeable flag setter accepting 'jvalue' values
-int WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
+Flag::Error WriteableFlags::set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg) {
jvalue new_value = *(jvalue*)value;
if (f->is_bool()) {
bool bvalue = (new_value.z == JNI_TRUE ? true : false);
@@ -251,17 +322,16 @@
oop str = JNIHandles::resolve_external_guard(new_value.l);
if (str == NULL) {
err_msg.print("flag value is missing");
- return MISSING_VALUE;
+ return Flag::MISSING_VALUE;
}
ccstr svalue = java_lang_String::as_utf8_string(str);
- int ret = WriteableFlags::set_ccstr_flag(f->_name, svalue, origin, err_msg);
- if (ret != SUCCESS) {
+ Flag::Error ret = WriteableFlags::set_ccstr_flag(f->_name, svalue, origin, err_msg);
+ if (ret != Flag::SUCCESS) {
FREE_C_HEAP_ARRAY(char, svalue);
}
return ret;
} else {
ShouldNotReachHere();
}
- return ERR_OTHER;
+ return Flag::ERR_OTHER;
}
-
--- a/hotspot/src/share/vm/services/writeableFlags.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/services/writeableFlags.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -26,64 +26,44 @@
#define SHARE_VM_SERVICES_WRITEABLEFLAG_HPP
class WriteableFlags : AllStatic {
-public:
- enum error {
- // no error
- SUCCESS,
- // flag name is missing
- MISSING_NAME,
- // flag value is missing
- MISSING_VALUE,
- // error parsing the textual form of the value
- WRONG_FORMAT,
- // flag is not writeable
- NON_WRITABLE,
- // flag value is outside of its bounds
- OUT_OF_BOUNDS,
- // there is no flag with the given name
- INVALID_FLAG,
- // other, unspecified error related to setting the flag
- ERR_OTHER
- } err;
-
private:
// a writeable flag setter accepting either 'jvalue' or 'char *' values
- static int set_flag(const char* name, const void* value, int(*setter)(Flag*, const void*, Flag::Flags, FormatBuffer<80>&), Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_flag(const char* name, const void* value, Flag::Error(*setter)(Flag*, const void*, Flag::Flags, FormatBuffer<80>&), Flag::Flags origin, FormatBuffer<80>& err_msg);
// a writeable flag setter accepting 'char *' values
- static int set_flag_from_char(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_flag_from_char(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// a writeable flag setter accepting 'jvalue' values
- static int set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_flag_from_jvalue(Flag* f, const void* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a boolean global flag
- static int set_bool_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_bool_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a int global flag
- static int set_int_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_int_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a uint global flag
- static int set_uint_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_uint_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a intx global flag
- static int set_intx_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_intx_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a uintx global flag
- static int set_uintx_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_uintx_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a uint64_t global flag
- static int set_uint64_t_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_uint64_t_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a size_t global flag using value from AttachOperation
- static int set_size_t_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_size_t_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a boolean global flag
- static int set_bool_flag(const char* name, bool value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_bool_flag(const char* name, bool value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a int global flag
- static int set_int_flag(const char* name, int value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_int_flag(const char* name, int value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a uint global flag
- static int set_uint_flag(const char* name, uint value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_uint_flag(const char* name, uint value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a intx global flag
- static int set_intx_flag(const char* name, intx value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_intx_flag(const char* name, intx value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a uintx global flag
- static int set_uintx_flag(const char* name, uintx value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_uintx_flag(const char* name, uintx value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a uint64_t global flag
- static int set_uint64_t_flag(const char* name, uint64_t value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_uint64_t_flag(const char* name, uint64_t value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a size_t global flag using value from AttachOperation
- static int set_size_t_flag(const char* name, size_t value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_size_t_flag(const char* name, size_t value, Flag::Flags origin, FormatBuffer<80>& err_msg);
// set a string global flag
- static int set_ccstr_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_ccstr_flag(const char* name, const char* value, Flag::Flags origin, FormatBuffer<80>& err_msg);
public:
/* sets a writeable flag to the provided value
@@ -91,15 +71,14 @@
* - return status is one of the WriteableFlags::err enum values
* - an eventual error message will be generated to the provided err_msg buffer
*/
- static int set_flag(const char* flag_name, const char* flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_flag(const char* flag_name, const char* flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg);
/* sets a writeable flag to the provided value
*
* - return status is one of the WriteableFlags::err enum values
* - an eventual error message will be generated to the provided err_msg buffer
*/
- static int set_flag(const char* flag_name, jvalue flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg);
+ static Flag::Error set_flag(const char* flag_name, jvalue flag_value, Flag::Flags origin, FormatBuffer<80>& err_msg);
};
#endif /* SHARE_VM_SERVICES_WRITEABLEFLAG_HPP */
-
--- a/hotspot/src/share/vm/trace/trace.xml Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/trace/trace.xml Thu Jun 25 09:48:50 2015 -0700
@@ -264,6 +264,15 @@
<structvalue type="ObjectSpace" field="toSpace" label="To Space"/>
</event>
+ <event id="G1HeapSummary" path="vm/gc/heap/g1_summary" label="G1 Heap Summary" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
+ <value type="GCWHEN" field="when" label="When" />
+
+ <value type="BYTES64" field="edenUsedSize" label="Eden Used Size" />
+ <value type="BYTES64" field="edenTotalSize" label="Eden Total Size" />
+ <value type="BYTES64" field="survivorUsedSize" label="Survivor Used Size" />
+ </event>
+
<event id="GCGarbageCollection" path="vm/gc/collector/garbage_collection" label="Garbage Collection"
description="Garbage collection performed by the JVM">
<value type="UINT" field="gcId" label="GC ID" relation="GC_ID" />
--- a/hotspot/src/share/vm/utilities/debug.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/utilities/debug.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -770,3 +770,31 @@
}
#endif // !PRODUCT
+
+//////////////////////////////////////////////////////////////////////////////
+// Test multiple STATIC_ASSERT forms in various scopes.
+
+#ifndef PRODUCT
+
+// namespace scope
+STATIC_ASSERT(true);
+STATIC_ASSERT(true);
+STATIC_ASSERT(1 == 1);
+STATIC_ASSERT(0 == 0);
+
+void test_multiple_static_assert_forms_in_function_scope() {
+ STATIC_ASSERT(true);
+ STATIC_ASSERT(true);
+ STATIC_ASSERT(0 == 0);
+ STATIC_ASSERT(1 == 1);
+}
+
+// class scope
+struct TestMultipleStaticAssertFormsInClassScope {
+ STATIC_ASSERT(true);
+ STATIC_ASSERT(true);
+ STATIC_ASSERT(0 == 0);
+ STATIC_ASSERT(1 == 1);
+};
+
+#endif // !PRODUCT
--- a/hotspot/src/share/vm/utilities/debug.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/utilities/debug.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -223,7 +223,8 @@
template<> struct STATIC_ASSERT_FAILURE<true> { enum { value = 1 }; };
#define STATIC_ASSERT(Cond) \
- typedef char STATIC_ASSERT_DUMMY_TYPE[ STATIC_ASSERT_FAILURE< (Cond) >::value ]
+ typedef char PASTE_TOKENS(STATIC_ASSERT_DUMMY_TYPE_, __LINE__)[ \
+ STATIC_ASSERT_FAILURE< (Cond) >::value ]
// out of shared space reporting
enum SharedSpaceType {
--- a/hotspot/src/share/vm/utilities/decoder.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/utilities/decoder.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -102,7 +102,7 @@
return _shared_decoder_lock;
}
-bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const char* modulepath) {
+bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const char* modulepath, bool demangle) {
assert(_shared_decoder_lock != NULL, "Just check");
bool error_handling_thread = os::current_thread_id() == VMError::first_error_tid;
MutexLockerEx locker(error_handling_thread ? NULL : _shared_decoder_lock, true);
@@ -110,7 +110,7 @@
get_error_handler_instance(): get_shared_instance();
assert(decoder != NULL, "null decoder");
- return decoder->decode(addr, buf, buflen, offset, modulepath);
+ return decoder->decode(addr, buf, buflen, offset, modulepath, demangle);
}
bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const void* base) {
--- a/hotspot/src/share/vm/utilities/decoder.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/utilities/decoder.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,8 +46,12 @@
// decode an pc address to corresponding function name and an offset from the beginning of
// the function
+ //
+ // Note: the 'base' variant does not demangle names. The
+ // demangling that was done systematically in the 'modulepath' variant
+ // is now optional.
virtual bool decode(address pc, char* buf, int buflen, int* offset,
- const char* modulepath = NULL) = 0;
+ const char* modulepath = NULL, bool demangle = true) = 0;
virtual bool decode(address pc, char* buf, int buflen, int* offset, const void* base) = 0;
// demangle a C++ symbol
@@ -81,7 +85,7 @@
~NullDecoder() {};
virtual bool decode(address pc, char* buf, int buflen, int* offset,
- const char* modulepath = NULL) {
+ const char* modulepath, bool demangle) {
return false;
}
@@ -101,7 +105,10 @@
class Decoder : AllStatic {
public:
- static bool decode(address pc, char* buf, int buflen, int* offset, const char* modulepath = NULL);
+ static bool decode(address pc, char* buf, int buflen, int* offset, const char* modulepath = NULL, bool demangle = true);
+ static bool decode(address pc, char* buf, int buflen, int* offset, bool demangle) {
+ return decode(pc, buf, buflen, offset, (const char*) NULL, demangle);
+ }
static bool decode(address pc, char* buf, int buflen, int* offset, const void* base);
static bool demangle(const char* symbol, char* buf, int buflen);
static bool can_decode_C_frame_in_vm();
--- a/hotspot/src/share/vm/utilities/decoder_elf.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/utilities/decoder_elf.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@
}
}
-bool ElfDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* filepath) {
+bool ElfDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* filepath, bool demangle_name) {
assert(filepath, "null file path");
assert(buf != NULL && buflen > 0, "Invalid buffer");
if (has_error()) return false;
@@ -46,7 +46,7 @@
if (!file->decode(addr, buf, buflen, offset)) {
return false;
}
- if (buf[0] != '\0') {
+ if (demangle_name && (buf[0] != '\0')) {
demangle(buf, buf, buflen);
}
return true;
--- a/hotspot/src/share/vm/utilities/decoder_elf.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/utilities/decoder_elf.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,7 @@
bool can_decode_C_frame_in_vm() const { return true; }
bool demangle(const char* symbol, char *buf, int buflen);
- bool decode(address addr, char *buf, int buflen, int* offset, const char* filepath = NULL);
+ bool decode(address addr, char *buf, int buflen, int* offset, const char* filepath, bool demangle);
bool decode(address addr, char *buf, int buflen, int* offset, const void *base) {
ShouldNotReachHere();
return false;
--- a/hotspot/src/share/vm/utilities/exceptions.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/utilities/exceptions.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -154,15 +154,21 @@
return;
}
+ if (h_exception->is_a(SystemDictionary::OutOfMemoryError_klass())) {
+ count_out_of_memory_exceptions(h_exception);
+ }
+
assert(h_exception->is_a(SystemDictionary::Throwable_klass()), "exception is not a subclass of java/lang/Throwable");
// set the pending exception
thread->set_pending_exception(h_exception(), file, line);
// vm log
- Events::log_exception(thread, "Exception <%s%s%s> (" INTPTR_FORMAT ") thrown at [%s, line %d]",
- h_exception->print_value_string(), message ? ": " : "", message ? message : "",
- (address)h_exception(), file, line);
+ if (LogEvents){
+ Events::log_exception(thread, "Exception <%s%s%s> (" INTPTR_FORMAT ") thrown at [%s, line %d]",
+ h_exception->print_value_string(), message ? ": " : "", message ? message : "",
+ (address)h_exception(), file, line);
+ }
}
@@ -228,6 +234,8 @@
if (StackTraceInThrowable) {
java_lang_Throwable::fill_in_stack_trace(exception, method());
}
+ // Increment counter for hs_err file reporting
+ Atomic::inc(&Exceptions::_stack_overflow_errors);
} else {
// if prior exception, throw that one instead
exception = Handle(THREAD, THREAD->pending_exception());
@@ -404,6 +412,44 @@
h_prot, to_utf8_safe);
}
+
+// Exception counting for hs_err file
+volatile int Exceptions::_stack_overflow_errors = 0;
+volatile int Exceptions::_out_of_memory_error_java_heap_errors = 0;
+volatile int Exceptions::_out_of_memory_error_metaspace_errors = 0;
+volatile int Exceptions::_out_of_memory_error_class_metaspace_errors = 0;
+
+void Exceptions::count_out_of_memory_exceptions(Handle exception) {
+ if (exception() == Universe::out_of_memory_error_metaspace()) {
+ Atomic::inc(&_out_of_memory_error_metaspace_errors);
+ } else if (exception() == Universe::out_of_memory_error_class_metaspace()) {
+ Atomic::inc(&_out_of_memory_error_class_metaspace_errors);
+ } else {
+ // everything else reported as java heap OOM
+ Atomic::inc(&_out_of_memory_error_java_heap_errors);
+ }
+}
+
+void print_oom_count(outputStream* st, const char *err, int count) {
+ if (count > 0) {
+ st->print_cr("OutOfMemoryError %s=%d", err, count);
+ }
+}
+
+bool Exceptions::has_exception_counts() {
+ return (_stack_overflow_errors + _out_of_memory_error_java_heap_errors +
+ _out_of_memory_error_metaspace_errors + _out_of_memory_error_class_metaspace_errors) > 0;
+}
+
+void Exceptions::print_exception_counts_on_error(outputStream* st) {
+ print_oom_count(st, "java_heap_errors", _out_of_memory_error_java_heap_errors);
+ print_oom_count(st, "metaspace_errors", _out_of_memory_error_metaspace_errors);
+ print_oom_count(st, "class_metaspace_errors", _out_of_memory_error_class_metaspace_errors);
+ if (_stack_overflow_errors > 0) {
+ st->print_cr("StackOverflowErrors=%d", _stack_overflow_errors);
+ }
+}
+
// Implementation of ExceptionMark
ExceptionMark::ExceptionMark(Thread*& thread) {
--- a/hotspot/src/share/vm/utilities/exceptions.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/utilities/exceptions.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -102,6 +102,11 @@
class Exceptions {
static bool special_exception(Thread *thread, const char* file, int line, Handle exception);
static bool special_exception(Thread* thread, const char* file, int line, Symbol* name, const char* message);
+
+ // Count out of memory errors that are interesting in error diagnosis
+ static volatile int _out_of_memory_error_java_heap_errors;
+ static volatile int _out_of_memory_error_metaspace_errors;
+ static volatile int _out_of_memory_error_class_metaspace_errors;
public:
// this enum is defined to indicate whether it is safe to
// ignore the encoding scheme of the original message string.
@@ -160,6 +165,14 @@
static void throw_stack_overflow_exception(Thread* thread, const char* file, int line, methodHandle method);
+ // Exception counting for error files of interesting exceptions that may have
+ // caused a problem for the jvm
+ static volatile int _stack_overflow_errors;
+
+ static bool has_exception_counts();
+ static void count_out_of_memory_exceptions(Handle exception);
+ static void print_exception_counts_on_error(outputStream* st);
+
// for AbortVMOnException flag
NOT_PRODUCT(static void debug_check_abort(Handle exception, const char* message = NULL);)
NOT_PRODUCT(static void debug_check_abort(const char *value_string, const char* message = NULL);)
--- a/hotspot/src/share/vm/utilities/macros.hpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/utilities/macros.hpp Thu Jun 25 09:48:50 2015 -0700
@@ -34,6 +34,15 @@
// Makes a string of the macro expansion of a
#define XSTR(a) STR(a)
+// Apply pre-processor token pasting to the expansions of x and y.
+// The token pasting operator (##) prevents its arguments from being
+// expanded. This macro allows expansion of its arguments before the
+// concatenation is performed. Note: One auxilliary level ought to be
+// sufficient, but two are used because of bugs in some preprocesors.
+#define PASTE_TOKENS(x, y) PASTE_TOKENS_AUX(x, y)
+#define PASTE_TOKENS_AUX(x, y) PASTE_TOKENS_AUX2(x, y)
+#define PASTE_TOKENS_AUX2(x, y) x ## y
+
// -DINCLUDE_<something>=0 | 1 can be specified on the command line to include
// or exclude functionality.
--- a/hotspot/src/share/vm/utilities/vmError.cpp Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Thu Jun 25 09:48:50 2015 -0700
@@ -714,6 +714,24 @@
st->cr();
}
+ STEP(182, "(printing number of OutOfMemoryError and StackOverflow exceptions)")
+
+ if (_verbose && Exceptions::has_exception_counts()) {
+ st->print_cr("OutOfMemory and StackOverflow Exception counts:");
+ Exceptions::print_exception_counts_on_error(st);
+ st->cr();
+ }
+
+ STEP(185, "(printing compressed oops mode")
+
+ if (_verbose && UseCompressedOops) {
+ Universe::print_compressed_oops_mode(st);
+ if (UseCompressedClassPointers) {
+ Metaspace::print_compressed_class_space(st);
+ }
+ st->cr();
+ }
+
STEP(190, "(printing heap information)" )
if (_verbose && Universe::is_fully_initialized()) {
@@ -798,7 +816,7 @@
STEP(250, "(printing CPU info)" )
if (_verbose) {
- os::print_cpu_info(st);
+ os::print_cpu_info(st, buf, sizeof(buf));
st->cr();
}
@@ -819,7 +837,7 @@
STEP(280, "(printing date and time)" )
if (_verbose) {
- os::print_date_and_time(st);
+ os::print_date_and_time(st, buf, sizeof(buf));
st->cr();
}
--- a/hotspot/test/TEST.groups Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/TEST.groups Thu Jun 25 09:48:50 2015 -0700
@@ -245,97 +245,6 @@
gc/whitebox/TestConcMarkCycleWB.java \
gc/arguments/TestG1ConcRefinementThreads.java
-# All tests that explicitly set the serial GC
-#
-needs_serialgc = \
- gc/TestSystemGC.java \
- gc/arguments/TestAlignmentToUseLargePages.java \
- gc/arguments/TestMaxNewSize.java \
- gc/arguments/TestSerialHeapSizeFlags.java \
- gc/arguments/TestUseCompressedOopsErgo.java \
- gc/serial/HeapChangeLogging.java \
- gc/metaspace/TestMetaspacePerfCounters.java \
- gc/metaspace/TestPerfCountersAndMemoryPools.java \
- gc/startup_warnings/TestSerialGC.java
-
-# All tests that explicitly set the parallel GC
-#
-needs_parallelgc = \
- gc/TestSystemGC.java \
- gc/arguments/TestAlignmentToUseLargePages.java \
- gc/arguments/TestMaxNewSize.java \
- gc/arguments/TestMinInitialErgonomics.java \
- gc/arguments/TestParallelGCThreads.java \
- gc/arguments/TestUseCompressedOopsErgo.java \
- gc/ergonomics/TestDynamicNumberOfGCThreads.java
- gc/metaspace/TestMetaspacePerfCounters.java \
- gc/parallel/ \
- gc/startup_warnings/TestParallelGC.java \
- gc/startup_warnings/TestParallelScavengeSerialOld.java
-
-# All tests that explicitly set the CMS GC
-#
-needs_cmsgc = \
- gc/6581734/Test6581734.java \
- gc/TestSystemGC.java \
- gc/arguments/TestAlignmentToUseLargePages.java \
- gc/arguments/TestCMSHeapSizeFlags.java \
- gc/arguments/TestMaxNewSize.java \
- gc/arguments/TestParallelGCThreads.java \
- gc/arguments/TestUseCompressedOopsErgo.java \
- gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java \
- gc/cms/ \
- gc/ergonomics/TestDynamicNumberOfGCThreads.java
- gc/startup_warnings/TestCMS.java \
- gc/startup_warnings/TestDefNewCMS.java \
- gc/startup_warnings/TestParNewCMS.java
-
-# All tests that explicitly set some GC
-#
-needs_gc = \
- :needs_g1gc \
- :needs_serialgc \
- :needs_parallelgc \
- :needs_cmsgc
-
-# All tests that do not set any GC explicitly
-#
-not_needs_gc = \
- :jdk \
- -:needs_gc
-
-# All tests that could be executed with the G1 GC without VM flags conflict
-#
-applicable_g1gc = \
- :jdk \
- -:needs_serialgc \
- -:needs_parallelgc \
- -:needs_cmsgc
-
-# All tests that could be executed with the serial GC without VM flags conflict
-#
-applicable_serialgc = \
- :jdk \
- -:needs_g1gc \
- -:needs_parallelgc \
- -:needs_cmsgc
-
-# All tests that could be executed with the parallel GC without VM flags conflict
-#
-applicable_parallelgc = \
- :jdk \
- -:needs_g1gc \
- -:needs_serialgc \
- -:needs_cmsgc
-
-# All tests that could be executed with the CMS GC without VM flags conflict
-#
-applicable_cmsgc = \
- :jdk \
- -:needs_g1gc \
- -:needs_serialgc \
- -:needs_parallelgc
-
hotspot_native_sanity = \
native_sanity
@@ -420,6 +329,7 @@
-runtime/SharedArchiveFile/DefaultUseWithClient.java \
-runtime/Thread/CancellableThreadTest.java \
-runtime/7158988/FieldMonitor.java \
+ -runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java \
sanity/ \
testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java
--- a/hotspot/test/compiler/c2/7200264/Test7200264.sh Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/compiler/c2/7200264/Test7200264.sh Thu Jun 25 09:48:50 2015 -0700
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -55,7 +55,8 @@
cp ${TESTSRC}${FS}TestIntVect.java .
${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} -d . TestIntVect.java
-${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:+PrintCompilation -XX:+TraceNewVectors TestIntVect > test.out 2>&1
+# CICompilerCount must be at least 2 with -TieredCompilation
+${TESTJAVA}${FS}bin${FS}java ${TESTOPTS} -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=2 -XX:+PrintCompilation -XX:+TraceNewVectors TestIntVect > test.out 2>&1
COUNT=`grep AddVI test.out | wc -l | awk '{print $1}'`
if [ $COUNT -lt 4 ]
--- a/hotspot/test/compiler/startup/NumCompilerThreadsCheck.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/compiler/startup/NumCompilerThreadsCheck.java Thu Jun 25 09:48:50 2015 -0700
@@ -37,7 +37,7 @@
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:CICompilerCount=-1");
OutputAnalyzer out = new OutputAnalyzer(pb.start());
- String expectedOutput = "CICompilerCount of -1 is invalid";
+ String expectedOutput = "outside the allowed range";
out.shouldContain(expectedOutput);
if (Platform.isZero()) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/CondCardMark/Basic.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8076987
+ * @bug 8078438
+ * @summary Verify UseCondCardMark works
+ * @library /testlibrary /../../test/lib
+ * @build Basic
+ * @run main/othervm -Xint Basic
+ * @run main/othervm -Xint -XX:+UseCondCardMark Basic
+ * @run main/othervm -XX:TieredStopAtLevel=1 Basic
+ * @run main/othervm -XX:TieredStopAtLevel=1 -XX:+UseCondCardMark Basic
+ * @run main/othervm -XX:TieredStopAtLevel=4 Basic
+ * @run main/othervm -XX:TieredStopAtLevel=4 -XX:+UseCondCardMark Basic
+ * @run main/othervm -XX:-TieredCompilation Basic
+ * @run main/othervm -XX:-TieredCompilation -XX:+UseCondCardMark Basic
+*/
+public class Basic {
+
+ static volatile MyObject sink;
+
+ public static void main(String args[]) {
+ final int COUNT = 10000000;
+ for (int c = 0; c < COUNT; c++) {
+ MyObject o = new MyObject();
+ o.x = c;
+ doStore(o);
+ }
+
+ if (sink.x != COUNT-1) {
+ throw new IllegalStateException("Failed");
+ }
+ }
+
+ public static void doStore(MyObject o) {
+ sink = o;
+ }
+
+ static class MyObject {
+ int x;
+ }
+
+}
--- a/hotspot/test/gc/arguments/TestHeapFreeRatio.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/arguments/TestHeapFreeRatio.java Thu Jun 25 09:48:50 2015 -0700
@@ -40,6 +40,7 @@
VALID,
MIN_INVALID,
MAX_INVALID,
+ OUT_OF_RANGE,
COMBINATION_INVALID
}
@@ -65,8 +66,13 @@
output.shouldContain("Error");
output.shouldHaveExitValue(1);
break;
+ case OUT_OF_RANGE:
+ output.shouldContain("outside the allowed range");
+ output.shouldContain("Error");
+ output.shouldHaveExitValue(1);
+ break;
case COMBINATION_INVALID:
- output.shouldContain("must be less than or equal to MaxHeapFreeRatio");
+ output.shouldContain("must be greater than or equal to MinHeapFreeRatio");
output.shouldContain("Error");
output.shouldHaveExitValue(1);
break;
@@ -82,23 +88,24 @@
testMinMaxFreeRatio( ".1", ".5", Validation.VALID);
testMinMaxFreeRatio( "0.5", "0.5", Validation.VALID);
- testMinMaxFreeRatio("-0.1", "0.5", Validation.MIN_INVALID);
- testMinMaxFreeRatio( "1.1", "0.5", Validation.MIN_INVALID);
testMinMaxFreeRatio("=0.1", "0.5", Validation.MIN_INVALID);
testMinMaxFreeRatio("0.1f", "0.5", Validation.MIN_INVALID);
testMinMaxFreeRatio(
"INVALID", "0.5", Validation.MIN_INVALID);
- testMinMaxFreeRatio(
- "2147483647", "0.5", Validation.MIN_INVALID);
- testMinMaxFreeRatio( "0.1", "-0.5", Validation.MAX_INVALID);
- testMinMaxFreeRatio( "0.1", "1.5", Validation.MAX_INVALID);
testMinMaxFreeRatio( "0.1", "0.5f", Validation.MAX_INVALID);
testMinMaxFreeRatio( "0.1", "=0.5", Validation.MAX_INVALID);
testMinMaxFreeRatio(
"0.1", "INVALID", Validation.MAX_INVALID);
+
+ testMinMaxFreeRatio("-0.1", "0.5", Validation.OUT_OF_RANGE);
+ testMinMaxFreeRatio( "1.1", "0.5", Validation.OUT_OF_RANGE);
testMinMaxFreeRatio(
- "0.1", "2147483647", Validation.MAX_INVALID);
+ "2147483647", "0.5", Validation.OUT_OF_RANGE);
+ testMinMaxFreeRatio( "0.1", "-0.5", Validation.OUT_OF_RANGE);
+ testMinMaxFreeRatio( "0.1", "1.5", Validation.OUT_OF_RANGE);
+ testMinMaxFreeRatio(
+ "0.1", "2147483647", Validation.OUT_OF_RANGE);
testMinMaxFreeRatio( "0.5", "0.1", Validation.COMBINATION_INVALID);
testMinMaxFreeRatio( ".5", ".10", Validation.COMBINATION_INVALID);
--- a/hotspot/test/gc/arguments/TestParallelGCThreads.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/arguments/TestParallelGCThreads.java Thu Jun 25 09:48:50 2015 -0700
@@ -24,7 +24,7 @@
/*
* @test TestParallelGCThreads
* @key gc
- * @bug 8059527
+ * @bug 8059527 8081382
* @summary Tests argument processing for ParallelGCThreads
* @library /testlibrary
* @modules java.base/sun.misc
@@ -37,7 +37,38 @@
public class TestParallelGCThreads {
public static void main(String args[]) throws Exception {
+ testFlags();
+ testDefaultValue();
+ }
+ private static final String flagName = "ParallelGCThreads";
+
+ // uint ParallelGCThreads = 23 {product}
+ private static final String printFlagsFinalPattern = " *uint *" + flagName + " *:?= *(\\d+) *\\{product\\} *";
+
+ public static void testDefaultValue() throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+UnlockExperimentalVMOptions", "-XX:+PrintFlagsFinal", "-version");
+
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ String value = output.firstMatch(printFlagsFinalPattern, 1);
+
+ try {
+ Asserts.assertNotNull(value, "Couldn't find uint flag " + flagName);
+
+ Long longValue = new Long(value);
+
+ // Sanity check that we got a non-zero value.
+ Asserts.assertNotEquals(longValue, "0");
+
+ output.shouldHaveExitValue(0);
+ } catch (Exception e) {
+ System.err.println(output.getOutput());
+ throw e;
+ }
+ }
+
+ public static void testFlags() throws Exception {
// For each parallel collector (G1, Parallel, ParNew/CMS)
for (String gc : new String[] {"G1", "Parallel", "ConcMarkSweep"}) {
@@ -54,6 +85,15 @@
Asserts.assertEQ(count, i, "Specifying ParallelGCThreads=" + i + " for " + gc + "GC does not set the thread count properly!");
}
}
+
+ // 4294967295 == (unsigned int) -1
+ // So setting ParallelGCThreads=4294967295 should give back 4294967295
+ // and setting ParallelGCThreads=4294967296 should give back 0. (SerialGC is ok with ParallelGCThreads=0)
+ for (long i = 4294967295L; i <= 4294967296L; i++) {
+ String[] flags = new String[] {"-XX:+UseSerialGC", "-XX:ParallelGCThreads=" + i, "-XX:+PrintFlagsFinal", "-version"};
+ long count = getParallelGCThreadCount(flags);
+ Asserts.assertEQ(count, i % 4294967296L, "Specifying ParallelGCThreads=" + i + " does not set the thread count properly!");
+ }
}
public static long getParallelGCThreadCount(String flags[]) throws Exception {
--- a/hotspot/test/gc/arguments/TestSelectDefaultGC.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/arguments/TestSelectDefaultGC.java Thu Jun 25 09:48:50 2015 -0700
@@ -36,11 +36,6 @@
import java.util.regex.*;
public class TestSelectDefaultGC {
- public static boolean versionStringContains(OutputAnalyzer output, String pattern) {
- Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(output.getStderr());
- return matcher.find();
- }
-
public static void assertVMOption(OutputAnalyzer output, String option, boolean value) {
output.shouldMatch(" " + option + " .*=.* " + value + " ");
}
@@ -51,14 +46,18 @@
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
- boolean isServerVM = versionStringContains(output, "Server VM");
+ boolean isServerVM = Platform.isServer();
+ boolean isEmbeddedVM = Platform.isEmbedded();
// Verify GC selection
- assertVMOption(output, "UseParallelGC", isServerVM);
- assertVMOption(output, "UseParallelOldGC", isServerVM);
+ // G1 is default for non-embedded server VMs
+ assertVMOption(output, "UseG1GC", isServerVM && !isEmbeddedVM);
+ // Parallel is default for embedded server VMs
+ assertVMOption(output, "UseParallelGC", isServerVM && isEmbeddedVM);
+ assertVMOption(output, "UseParallelOldGC", isServerVM && isEmbeddedVM);
+ // Serial is default for non-server VMs
assertVMOption(output, "UseSerialGC", !isServerVM);
assertVMOption(output, "UseConcMarkSweepGC", false);
- assertVMOption(output, "UseG1GC", false);
assertVMOption(output, "UseParNewGC", false);
}
}
--- a/hotspot/test/gc/arguments/TestSurvivorAlignmentInBytesOption.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/arguments/TestSurvivorAlignmentInBytesOption.java Thu Jun 25 09:48:50 2015 -0700
@@ -45,9 +45,9 @@
String optionIsExperimental
= CommandLineOptionTest.getExperimentalOptionErrorMessage(
optionName);
- String valueIsTooSmall= ".*SurvivorAlignmentInBytes=.*must be greater"
- + " than ObjectAlignmentInBytes.*";
- String mustBePowerOf2 = ".*SurvivorAlignmentInBytes=.*must be "
+ String valueIsTooSmall= ".*SurvivorAlignmentInBytes.*must be greater"
+ + " than or equal to ObjectAlignmentInBytes.*";
+ String mustBePowerOf2 = ".*SurvivorAlignmentInBytes.*must be "
+ "power of 2.*";
// Verify that without -XX:+UnlockExperimentalVMOptions usage of
--- a/hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/g1/TestLargePageUseForAuxMemory.java Thu Jun 25 09:48:50 2015 -0700
@@ -24,25 +24,28 @@
/*
* @test TestLargePageUseForAuxMemory.java
* @summary Test that auxiliary data structures are allocated using large pages if available.
- * @bug 8058354
+ * @bug 8058354 8079208
* @key gc
* @library /testlibrary /../../test/lib
* @requires (vm.gc=="G1" | vm.gc=="null")
* @build jdk.test.lib.* sun.hotspot.WhiteBox
* @build TestLargePageUseForAuxMemory
- * @ignore 8079208
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+WhiteBoxAPI -XX:+IgnoreUnrecognizedVMOptions -XX:+UseLargePages TestLargePageUseForAuxMemory
*/
+import java.lang.Math;
+
import jdk.test.lib.*;
+import jdk.test.lib.Asserts;
import sun.hotspot.WhiteBox;
public class TestLargePageUseForAuxMemory {
- static final int HEAP_REGION_SIZE = 4 * 1024 * 1024;
+ static final long HEAP_REGION_SIZE = 1 * 1024 * 1024;
static long largePageSize;
static long smallPageSize;
+ static long allocGranularity;
static void checkSmallTables(OutputAnalyzer output, long expectedPageSize) throws Exception {
output.shouldContain("G1 'Block offset table': pg_sz=" + expectedPageSize);
@@ -54,16 +57,18 @@
output.shouldContain("G1 'Next Bitmap': pg_sz=" + expectedPageSize);
}
- static void testVM(long heapsize, boolean cardsShouldUseLargePages, boolean bitmapShouldUseLargePages) throws Exception {
+ static void testVM(String what, long heapsize, boolean cardsShouldUseLargePages, boolean bitmapShouldUseLargePages) throws Exception {
+ System.out.println(what + " heapsize " + heapsize + " card table should use large pages " + cardsShouldUseLargePages + " " +
+ "bitmaps should use large pages " + bitmapShouldUseLargePages);
ProcessBuilder pb;
// Test with large page enabled.
pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
"-XX:G1HeapRegionSize=" + HEAP_REGION_SIZE,
- "-Xms" + 10 * HEAP_REGION_SIZE,
+ "-Xms" + heapsize,
"-Xmx" + heapsize,
"-XX:+TracePageSizes",
"-XX:+UseLargePages",
- "-XX:+IgnoreUnrecognizedVMOptions", // there is on ObjectAlignmentInBytes in 32 bit builds
+ "-XX:+IgnoreUnrecognizedVMOptions", // there is no ObjectAlignmentInBytes in 32 bit builds
"-XX:ObjectAlignmentInBytes=8",
"-version");
@@ -75,11 +80,11 @@
// Test with large page disabled.
pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
"-XX:G1HeapRegionSize=" + HEAP_REGION_SIZE,
- "-Xms" + 10 * HEAP_REGION_SIZE,
+ "-Xms" + heapsize,
"-Xmx" + heapsize,
"-XX:+TracePageSizes",
"-XX:-UseLargePages",
- "-XX:+IgnoreUnrecognizedVMOptions", // there is on ObjectAlignmentInBytes in 32 bit builds
+ "-XX:+IgnoreUnrecognizedVMOptions", // there is no ObjectAlignmentInBytes in 32 bit builds
"-XX:ObjectAlignmentInBytes=8",
"-version");
@@ -98,6 +103,7 @@
WhiteBox wb = WhiteBox.getWhiteBox();
smallPageSize = wb.getVMPageSize();
largePageSize = wb.getVMLargePageSize();
+ allocGranularity = wb.getVMAllocationGranularity();
if (largePageSize == 0) {
System.out.println("Skip tests because large page support does not seem to be available on this platform.");
@@ -112,20 +118,26 @@
final int cardSize = 512;
final long heapSizeForCardTableUsingLargePages = largePageSize * cardSize;
+ final long heapSizeDiffForCardTable = Math.max(Math.max(allocGranularity * cardSize, HEAP_REGION_SIZE), largePageSize);
- testVM(heapSizeForCardTableUsingLargePages, true, true);
- testVM(heapSizeForCardTableUsingLargePages + HEAP_REGION_SIZE, true, true);
- testVM(heapSizeForCardTableUsingLargePages - HEAP_REGION_SIZE, false, true);
+ Asserts.assertGT(heapSizeForCardTableUsingLargePages, heapSizeDiffForCardTable,
+ "To test we would require to use an invalid heap size");
+ testVM("case1: card table and bitmap use large pages (barely)", heapSizeForCardTableUsingLargePages, true, true);
+ testVM("case2: card table and bitmap use large pages (extra slack)", heapSizeForCardTableUsingLargePages + heapSizeDiffForCardTable, true, true);
+ testVM("case3: only bitmap uses large pages (barely not)", heapSizeForCardTableUsingLargePages - heapSizeDiffForCardTable, false, true);
}
// Minimum heap requirement to get large pages for bitmaps is 128M heap. This seems okay to test
// everywhere.
final int bitmapTranslationFactor = 8 * 8; // ObjectAlignmentInBytes * BitsPerByte
final long heapSizeForBitmapUsingLargePages = largePageSize * bitmapTranslationFactor;
+ final long heapSizeDiffForBitmap = Math.max(Math.max(allocGranularity * bitmapTranslationFactor, HEAP_REGION_SIZE), largePageSize);
- testVM(heapSizeForBitmapUsingLargePages, false, true);
- testVM(heapSizeForBitmapUsingLargePages + HEAP_REGION_SIZE, false, true);
- testVM(heapSizeForBitmapUsingLargePages - HEAP_REGION_SIZE, false, false);
+ Asserts.assertGT(heapSizeForBitmapUsingLargePages, heapSizeDiffForBitmap,
+ "To test we would require to use an invalid heap size");
+
+ testVM("case4: only bitmap uses large pages (barely)", heapSizeForBitmapUsingLargePages, false, true);
+ testVM("case5: only bitmap uses large pages (extra slack)", heapSizeForBitmapUsingLargePages + heapSizeDiffForBitmap, false, true);
+ testVM("case6: nothing uses large pages (barely not)", heapSizeForBitmapUsingLargePages - heapSizeDiffForBitmap, false, false);
}
}
-
--- a/hotspot/test/gc/g1/TestStringDeduplicationTools.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/g1/TestStringDeduplicationTools.java Thu Jun 25 09:48:50 2015 -0700
@@ -412,16 +412,14 @@
output = DeduplicationTest.run(SmallNumberOfStrings,
TooLowAgeThreshold,
YoungGC);
- output.shouldContain("StringDeduplicationAgeThreshold of " + TooLowAgeThreshold +
- " is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold);
+ output.shouldContain("outside the allowed range");
output.shouldHaveExitValue(1);
// Test with too high age threshold
output = DeduplicationTest.run(SmallNumberOfStrings,
TooHighAgeThreshold,
YoungGC);
- output.shouldContain("StringDeduplicationAgeThreshold of " + TooHighAgeThreshold +
- " is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold);
+ output.shouldContain("outside the allowed range");
output.shouldHaveExitValue(1);
}
--- a/hotspot/test/gc/survivorAlignment/TestAllocationInEden.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/survivorAlignment/TestAllocationInEden.java Thu Jun 25 09:48:50 2015 -0700
@@ -35,42 +35,42 @@
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
- * -XX:SurvivorAlignmentInBytes=32 -XX:-UseTLAB
+ * -XX:SurvivorAlignmentInBytes=32 -XX:-UseTLAB -XX:-ResizePLAB
* -XX:OldSize=128m -XX:MaxHeapSize=192m
* -XX:-ExplicitGCInvokesConcurrent
* TestAllocationInEden 10m 9 EDEN
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
- * -XX:SurvivorAlignmentInBytes=32 -XX:-UseTLAB
+ * -XX:SurvivorAlignmentInBytes=32 -XX:-UseTLAB -XX:-ResizePLAB
* -XX:OldSize=128m -XX:MaxHeapSize=192m
* -XX:-ExplicitGCInvokesConcurrent
* TestAllocationInEden 10m 47 EDEN
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
- * -XX:SurvivorAlignmentInBytes=64 -XX:-UseTLAB
+ * -XX:SurvivorAlignmentInBytes=64 -XX:-UseTLAB -XX:-ResizePLAB
* -XX:OldSize=128m -XX:MaxHeapSize=192m
* -XX:-ExplicitGCInvokesConcurrent
* TestAllocationInEden 10m 9 EDEN
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
- * -XX:SurvivorAlignmentInBytes=64 -XX:-UseTLAB
+ * -XX:SurvivorAlignmentInBytes=64 -XX:-UseTLAB -XX:-ResizePLAB
* -XX:OldSize=128m -XX:MaxHeapSize=192m
* -XX:-ExplicitGCInvokesConcurrent
* TestAllocationInEden 10m 87 EDEN
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
- * -XX:SurvivorAlignmentInBytes=128 -XX:-UseTLAB
+ * -XX:SurvivorAlignmentInBytes=128 -XX:-UseTLAB -XX:-ResizePLAB
* -XX:OldSize=128m -XX:MaxHeapSize=192m
* -XX:-ExplicitGCInvokesConcurrent
* TestAllocationInEden 10m 9 EDEN
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
- * -XX:SurvivorAlignmentInBytes=128 -XX:-UseTLAB
+ * -XX:SurvivorAlignmentInBytes=128 -XX:-UseTLAB -XX:-ResizePLAB
* -XX:OldSize=128m -XX:MaxHeapSize=192m
* -XX:-ExplicitGCInvokesConcurrent
* TestAllocationInEden 10m 147 EDEN
--- a/hotspot/test/gc/survivorAlignment/TestPromotionFromEdenToTenured.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionFromEdenToTenured.java Thu Jun 25 09:48:50 2015 -0700
@@ -36,42 +36,42 @@
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:OldSize=32m -XX:MaxHeapSize=96m -XX:SurvivorRatio=1
- * -XX:-ExplicitGCInvokesConcurrent
+ * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=32
* TestPromotionFromEdenToTenured 10m 9 TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:OldSize=32m -XX:MaxHeapSize=96m -XX:SurvivorRatio=1
- * -XX:-ExplicitGCInvokesConcurrent
+ * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=32
* TestPromotionFromEdenToTenured 10m 47 TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:OldSize=32m -XX:MaxHeapSize=96m
- * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent
+ * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=64
* TestPromotionFromEdenToTenured 10m 9 TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:OldSize=32m -XX:MaxHeapSize=128m
- * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent
+ * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=64
* TestPromotionFromEdenToTenured 10m 87 TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:OldSize=32M -XX:MaxHeapSize=96m -XX:SurvivorRatio=1
- * -XX:-ExplicitGCInvokesConcurrent
+ * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=128
* TestPromotionFromEdenToTenured 10m 9 TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m
* -XX:OldSize=32m -XX:MaxHeapSize=96m -XX:SurvivorRatio=1
- * -XX:-ExplicitGCInvokesConcurrent
+ * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=128
* TestPromotionFromEdenToTenured 10m 147 TENURED
--- a/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterFullGC.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterFullGC.java Thu Jun 25 09:48:50 2015 -0700
@@ -36,13 +36,13 @@
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
* -XX:OldSize=32m -XX:MaxHeapSize=160m
- * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent
+ * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=32
* TestPromotionFromSurvivorToTenuredAfterFullGC 10m 9 TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
- * -XX:OldSize=32m -XX:MaxHeapSize=160m
+ * -XX:OldSize=32m -XX:MaxHeapSize=160m -XX:-ResizePLAB
* -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=32
@@ -51,14 +51,14 @@
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=200m -XX:MaxNewSize=200m
* -XX:OldSize=32m -XX:MaxHeapSize=232m
- * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent
+ * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=64
* TestPromotionFromSurvivorToTenuredAfterFullGC 10m 9 TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
* -XX:OldSize=32m -XX:MaxHeapSize=160m
- * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent
+ * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=64
* TestPromotionFromSurvivorToTenuredAfterFullGC 20m 87
@@ -66,7 +66,7 @@
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=256m -XX:MaxNewSize=256m
* -XX:OldSize=32M -XX:MaxHeapSize=288m
- * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent
+ * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=128
* TestPromotionFromSurvivorToTenuredAfterFullGC 10m 9
@@ -74,7 +74,7 @@
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
* -XX:OldSize=32m -XX:MaxHeapSize=160m
- * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent
+ * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=128
* TestPromotionFromSurvivorToTenuredAfterFullGC 20m 147
--- a/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java Thu Jun 25 09:48:50 2015 -0700
@@ -36,7 +36,7 @@
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
- * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1
+ * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 -XX:-ResizePLAB
* -XX:-ExplicitGCInvokesConcurrent
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=32
@@ -44,7 +44,7 @@
* TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
- * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1
+ * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 -XX:-ResizePLAB
* -XX:-ExplicitGCInvokesConcurrent
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=32
@@ -52,7 +52,7 @@
* TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=200m -XX:MaxNewSize=200m
- * -XX:OldSize=32M -XX:MaxHeapSize=232m -XX:SurvivorRatio=1
+ * -XX:OldSize=32M -XX:MaxHeapSize=232m -XX:SurvivorRatio=1 -XX:-ResizePLAB
* -XX:-ExplicitGCInvokesConcurrent
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=64
@@ -60,7 +60,7 @@
* TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
- * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1
+ * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 -XX:-ResizePLAB
* -XX:-ExplicitGCInvokesConcurrent
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=64
@@ -68,7 +68,7 @@
* TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=256m -XX:MaxNewSize=256m
- * -XX:OldSize=32M -XX:MaxHeapSize=288m -XX:SurvivorRatio=1
+ * -XX:OldSize=32M -XX:MaxHeapSize=288m -XX:SurvivorRatio=1 -XX:-ResizePLAB
* -XX:-ExplicitGCInvokesConcurrent
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=128
@@ -76,7 +76,7 @@
* TENURED
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
- * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1
+ * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 -XX:-ResizePLAB
* -XX:-ExplicitGCInvokesConcurrent
* -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=128
--- a/hotspot/test/gc/survivorAlignment/TestPromotionToSurvivor.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/gc/survivorAlignment/TestPromotionToSurvivor.java Thu Jun 25 09:48:50 2015 -0700
@@ -37,37 +37,37 @@
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=32 -XX:OldSize=128m
- * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent
+ * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* TestPromotionToSurvivor 10m 9 SURVIVOR
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=32 -XX:OldSize=128m
- * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent
+ * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* TestPromotionToSurvivor 20m 47 SURVIVOR
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=64 -XX:OldSize=128m
- * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent
+ * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* TestPromotionToSurvivor 8m 9 SURVIVOR
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=64 -XX:OldSize=128m
- * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent
+ * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* TestPromotionToSurvivor 20m 87 SURVIVOR
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=256m -XX:MaxNewSize=256m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=128 -XX:OldSize=128m
- * -XX:MaxHeapSize=384m -XX:-ExplicitGCInvokesConcurrent
+ * -XX:MaxHeapSize=384m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* TestPromotionToSurvivor 10m 9 SURVIVOR
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m
* -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions
* -XX:SurvivorAlignmentInBytes=128 -XX:OldSize=128m
- * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent
+ * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB
* TestPromotionToSurvivor 20m 147 SURVIVOR
*/
public class TestPromotionToSurvivor {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestJcmdOutput.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Verify jcmd error message for out-of-range value and for
+ * value which is not allowed by constraint. Also check that
+ * jcmd does not print an error message to the target process output.
+ * @library /testlibrary
+ * @modules java.base/sun.misc
+ * java.management
+ * jdk.management
+ * @run main TestJcmdOutput
+ */
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.DynamicVMOption;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.dcmd.PidJcmdExecutor;
+
+public class TestJcmdOutput {
+
+ /* Message printed by jcmd for value which is out-of-range */
+ static final String JCMD_OUT_OF_RANGE_MESSAGE = "error: must have value in range";
+ /* Message printed by jcmd for value which is not allowed by constraint */
+ static final String JCMD_CONSTRAINT_MESSAGE = "value violates its flag's constraint";
+
+ public static void main(String[] args) throws Exception {
+ OutputAnalyzer output;
+
+ System.out.println("Verify jcmd error message and that jcmd does not write errors to the target process output");
+ output = new OutputAnalyzer((ProcessTools.createJavaProcessBuilder(
+ "-Dtest.jdk=" + System.getProperty("test.jdk"),
+ "-XX:MinHeapFreeRatio=20", "-XX:MaxHeapFreeRatio=80", runJcmd.class.getName())).start());
+
+ output.shouldHaveExitValue(0);
+ /* Verify that jcmd not print error message to the target process output */
+ output.shouldNotContain(JCMD_OUT_OF_RANGE_MESSAGE);
+ output.shouldNotContain(JCMD_CONSTRAINT_MESSAGE);
+ }
+
+ public static class runJcmd {
+
+ public static void main(String[] args) throws Exception {
+ int minHeapFreeRatio = new Integer((new DynamicVMOption("MinHeapFreeRatio")).getValue());
+ int maxHeapFreeRatio = new Integer((new DynamicVMOption("MaxHeapFreeRatio")).getValue());
+ PidJcmdExecutor executor = new PidJcmdExecutor();
+
+ Asserts.assertGT(minHeapFreeRatio, 0, "MinHeapFreeRatio must be greater than 0");
+ Asserts.assertLT(maxHeapFreeRatio, 100, "MaxHeapFreeRatio must be less than 100");
+
+ /* Check out-of-range values */
+ executor.execute("VM.set_flag MinHeapFreeRatio -1", true).shouldContain(JCMD_OUT_OF_RANGE_MESSAGE);
+ executor.execute("VM.set_flag MaxHeapFreeRatio 101", true).shouldContain(JCMD_OUT_OF_RANGE_MESSAGE);
+
+ /* Check values which not allowed by constraint */
+ executor.execute(
+ String.format("VM.set_flag MinHeapFreeRatio %d", maxHeapFreeRatio + 1), true)
+ .shouldContain(JCMD_CONSTRAINT_MESSAGE);
+ executor.execute(
+ String.format("VM.set_flag MaxHeapFreeRatio %d", minHeapFreeRatio - 1), true)
+ .shouldContain(JCMD_CONSTRAINT_MESSAGE);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test VM Options with ranges
+ * @library /testlibrary /runtime/CommandLine/OptionsValidation/common
+ * @modules java.base/sun.misc
+ * java.management
+ * jdk.attach
+ * jdk.management/sun.tools.attach
+ * @run main/othervm/timeout=600 TestOptionsWithRanges
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import jdk.test.lib.Asserts;
+import optionsvalidation.JVMOption;
+import optionsvalidation.JVMOptionsUtils;
+
+public class TestOptionsWithRanges {
+
+ public static void main(String[] args) throws Exception {
+ int failedTests;
+ Map<String, JVMOption> allOptionsAsMap = JVMOptionsUtils.getOptionsWithRangeAsMap();
+ List<JVMOption> allOptions;
+
+ /*
+ * Remove CICompilerCount from testing because currently it can hang system
+ */
+ allOptionsAsMap.remove("CICompilerCount");
+
+ allOptions = new ArrayList<>(allOptionsAsMap.values());
+
+ Asserts.assertGT(allOptions.size(), 0, "Options with ranges not found!");
+
+ System.out.println("Parsed " + allOptions.size() + " options with ranges. Start test!");
+
+ failedTests = JVMOptionsUtils.runCommandLineTests(allOptions);
+
+ Asserts.assertEQ(failedTests, 0,
+ String.format("%d tests failed! %s", failedTests, JVMOptionsUtils.getMessageWithFailures()));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRangesDynamic.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test writeable VM Options with ranges.
+ * @library /testlibrary /runtime/CommandLine/OptionsValidation/common
+ * @modules java.base/sun.misc
+ * java.management
+ * jdk.attach
+ * jdk.management/sun.tools.attach
+ * @run main/othervm -XX:MinHeapFreeRatio=0 -XX:MaxHeapFreeRatio=100 TestOptionsWithRangesDynamic
+ */
+
+import java.util.List;
+import jdk.test.lib.Asserts;
+import optionsvalidation.JVMOption;
+import optionsvalidation.JVMOptionsUtils;
+
+public class TestOptionsWithRangesDynamic {
+
+ public static void main(String[] args) throws Exception {
+ int failedTests;
+ List<JVMOption> allWriteableOptions;
+
+ /* Get only writeable options */
+ allWriteableOptions = JVMOptionsUtils.getOptionsWithRange(origin -> (origin.contains("manageable") || origin.contains("rw")));
+
+ Asserts.assertGT(allWriteableOptions.size(), 0, "Options with ranges not found!");
+
+ System.out.println("Test " + allWriteableOptions.size() + " writeable options with ranges. Start test!");
+
+ failedTests = JVMOptionsUtils.runDynamicTests(allWriteableOptions);
+
+ failedTests += JVMOptionsUtils.runJcmdTests(allWriteableOptions);
+
+ failedTests += JVMOptionsUtils.runAttachTests(allWriteableOptions);
+
+ Asserts.assertEQ(failedTests, 0,
+ String.format("%d tests failed! %s", failedTests, JVMOptionsUtils.getMessageWithFailures()));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/DoubleJVMOption.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package optionsvalidation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DoubleJVMOption extends JVMOption {
+
+ /**
+ * Additional double values to test
+ */
+ private static final double ADDITIONAL_TEST_DOUBLE_NEGATIVE = -1.5;
+ private static final double ADDITIONAL_TEST_DOUBLE_ZERO = 0.0;
+ private static final double ADDITIONAL_TEST_DOUBLE_POSITIVE = 1.75;
+
+ /**
+ * Mininum option value
+ */
+ private double min;
+ /**
+ * Maximum option value
+ */
+ private double max;
+
+ /**
+ * Initialize double option with passed name
+ *
+ * @param name name of the option
+ */
+ DoubleJVMOption(String name) {
+ this.name = name;
+ min = Double.MIN_VALUE;
+ max = Double.MAX_VALUE;
+ }
+
+ /**
+ * Initialize double option with passed name, min and max values
+ *
+ * @param name name of the option
+ * @param min minimum value of the option
+ * @param max maximum value of the option
+ */
+ public DoubleJVMOption(String name, double min, double max) {
+ this(name);
+ this.min = min;
+ this.max = max;
+ }
+
+ /**
+ * Set new minimum option value
+ *
+ * @param min new minimum value
+ */
+ @Override
+ void setMin(String min) {
+ this.min = new Double(min);
+ }
+
+ /**
+ * Get string with minimum value of the option
+ *
+ * @return string with minimum value of the option
+ */
+ @Override
+ String getMin() {
+ return formatValue(min);
+ }
+
+ /**
+ * Set new maximum option value
+ *
+ * @param max new maximum value
+ */
+ @Override
+ void setMax(String max) {
+ this.max = new Double(max);
+ }
+
+ /**
+ * Get string with maximum value of the option
+ *
+ * @return string with maximum value of the option
+ */
+ @Override
+ String getMax() {
+ return formatValue(max);
+ }
+
+ private String formatValue(double value) {
+ return String.format("%f", value);
+ }
+
+ /**
+ * Return list of strings with valid option values which used for testing
+ * using jcmd, attach and etc.
+ *
+ * @return list of strings which contain valid values for option
+ */
+ @Override
+ protected List<String> getValidValues() {
+ List<String> validValues = new ArrayList<>();
+
+ validValues.add(formatValue(min));
+ validValues.add(formatValue(max));
+
+ if ((Double.compare(min, ADDITIONAL_TEST_DOUBLE_NEGATIVE) < 0)
+ && (Double.compare(max, ADDITIONAL_TEST_DOUBLE_NEGATIVE) > 0)) {
+ validValues.add(formatValue(ADDITIONAL_TEST_DOUBLE_NEGATIVE));
+ }
+
+ if ((Double.compare(min, ADDITIONAL_TEST_DOUBLE_ZERO) < 0)
+ && (Double.compare(max, ADDITIONAL_TEST_DOUBLE_ZERO) > 0)) {
+ validValues.add(formatValue(ADDITIONAL_TEST_DOUBLE_ZERO));
+ }
+
+ if ((Double.compare(min, ADDITIONAL_TEST_DOUBLE_POSITIVE) < 0)
+ && (Double.compare(max, ADDITIONAL_TEST_DOUBLE_POSITIVE) > 0)) {
+ validValues.add(formatValue(ADDITIONAL_TEST_DOUBLE_POSITIVE));
+ }
+
+ return validValues;
+ }
+
+ /**
+ * Return list of strings with invalid option values which used for testing
+ * using jcmd, attach and etc.
+ *
+ * @return list of strings which contain invalid values for option
+ */
+ @Override
+ protected List<String> getInvalidValues() {
+ List<String> invalidValues = new ArrayList<>();
+
+ if (withRange) {
+ /* Return invalid values only for options which have defined range in VM */
+ if (Double.compare(min, Double.MIN_VALUE) != 0) {
+ if ((Double.compare(min, 0.0) > 0)
+ && (Double.isNaN(min * 0.999) == false)) {
+ invalidValues.add(formatValue(min * 0.999));
+ } else if ((Double.compare(min, 0.0) < 0)
+ && (Double.isNaN(min * 1.001) == false)) {
+ invalidValues.add(formatValue(min * 1.001));
+ }
+ }
+
+ if (Double.compare(max, Double.MAX_VALUE) != 0) {
+ if ((Double.compare(max, 0.0) > 0)
+ && (Double.isNaN(max * 1.001) == false)) {
+ invalidValues.add(formatValue(max * 1.001));
+ } else if ((Double.compare(max, 0.0) < 0)
+ && (Double.isNaN(max * 0.999) == false)) {
+ invalidValues.add(formatValue(max * 0.999));
+ }
+ }
+ }
+
+ return invalidValues;
+ }
+
+ /**
+ * Return expected error message for option with value "value" when it used
+ * on command line with passed value
+ *
+ * @param value option value
+ * @return expected error message
+ */
+ @Override
+ protected String getErrorMessageCommandLine(String value) {
+ String errorMsg;
+
+ if (withRange) {
+ /* Option have defined range in VM */
+ errorMsg = "is outside the allowed range";
+ } else {
+ errorMsg = "";
+ }
+
+ return errorMsg;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/IntJVMOption.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package optionsvalidation;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import jdk.test.lib.Platform;
+
+public class IntJVMOption extends JVMOption {
+
+ private static final BigInteger MIN_LONG;
+ private static final BigInteger MAX_LONG;
+ private static final BigInteger MAX_UNSIGNED_LONG;
+ private static final BigInteger MAX_UNSIGNED_LONG_64;
+ private static final BigInteger MINUS_ONE = new BigInteger("-1");
+ private static final BigInteger TWO = new BigInteger("2");
+ private static final BigInteger MIN_4_BYTE_INT = new BigInteger("-2147483648");
+ private static final BigInteger MAX_4_BYTE_INT = new BigInteger("2147483647");
+ private static final BigInteger MAX_4_BYTE_INT_PLUS_ONE = new BigInteger("2147483648");
+ private static final BigInteger MAX_4_BYTE_UNSIGNED_INT = new BigInteger("4294967295");
+ private static final BigInteger MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE = new BigInteger("4294967296");
+
+ /**
+ * Mininum option value
+ */
+ private BigInteger min;
+
+ /**
+ * Maximum option value
+ */
+ private BigInteger max;
+
+ /**
+ * Option type: intx, uintx, size_t or uint64_t
+ */
+ private String type;
+
+ /**
+ * Is this value signed or unsigned
+ */
+ private boolean unsigned;
+
+ /**
+ * Is this 32 bit type
+ */
+ private boolean is32Bit = false;
+
+ /**
+ * Is this value 64 bit unsigned
+ */
+ private boolean uint64 = false;
+
+ static {
+ if (Platform.is32bit()) {
+ MIN_LONG = new BigInteger(String.valueOf(Integer.MIN_VALUE));
+ MAX_LONG = new BigInteger(String.valueOf(Integer.MAX_VALUE));
+ MAX_UNSIGNED_LONG = MAX_LONG.multiply(TWO).add(BigInteger.ONE);
+ } else {
+ MIN_LONG = new BigInteger(String.valueOf(Long.MIN_VALUE));
+ MAX_LONG = new BigInteger(String.valueOf(Long.MAX_VALUE));
+ MAX_UNSIGNED_LONG = MAX_LONG.multiply(TWO).add(BigInteger.ONE);
+ }
+
+ MAX_UNSIGNED_LONG_64 = (new BigInteger(String.valueOf(Long.MAX_VALUE)))
+ .multiply(TWO).add(BigInteger.ONE);
+ }
+
+ private IntJVMOption() {
+ type = "";
+ }
+
+ /**
+ * Initialize new integer option with given type. Type can be: INTX -
+ * integer signed option UINTX - unsigned integer option UINT64_T - unsigned
+ * 64 bit integer option
+ *
+ * @param name name of the option
+ * @param type type of the option
+ */
+ IntJVMOption(String name, String type) {
+ this.name = name;
+ this.type = type;
+
+ switch (type) {
+ case "uint64_t":
+ unsigned = true;
+ uint64 = true;
+ max = MAX_UNSIGNED_LONG_64;
+ break;
+ case "uintx":
+ case "size_t":
+ unsigned = true;
+ max = MAX_UNSIGNED_LONG;
+ break;
+ case "uint":
+ unsigned = true;
+ is32Bit = true;
+ max = MAX_4_BYTE_UNSIGNED_INT;
+ break;
+ case "int":
+ min = MIN_4_BYTE_INT;
+ max = MAX_4_BYTE_INT;
+ is32Bit = true;
+ break;
+ default:
+ min = MIN_LONG;
+ max = MAX_LONG;
+ break;
+ }
+
+ if (unsigned) {
+ min = BigInteger.ZERO;
+ }
+ }
+
+ /**
+ * Initialize integer option with passed name, min and max values. Min and
+ * max are string because they can be very big, bigger than long.
+ *
+ * @param name name of the option
+ * @param min minimum value of the option
+ * @param max maximum value of the option
+ */
+ public IntJVMOption(String name, String min, String max) {
+ this();
+ this.name = name;
+ this.min = new BigInteger(min);
+ this.max = new BigInteger(max);
+ }
+
+ /**
+ * Set new minimum option value
+ *
+ * @param min new minimum value
+ */
+ @Override
+ void setMin(String min) {
+ this.min = new BigInteger(min);
+ }
+
+ /**
+ * Get string with minimum value of the option
+ *
+ * @return string with minimum value of the option
+ */
+ @Override
+ String getMin() {
+ return min.toString();
+ }
+
+ /**
+ * Set new maximum option value
+ *
+ * @param max new maximum value
+ */
+ @Override
+ void setMax(String max) {
+ this.max = new BigInteger(max);
+ }
+
+ /**
+ * Get string with maximum value of the option
+ *
+ * @return string with maximum value of the option
+ */
+ @Override
+ String getMax() {
+ return max.toString();
+ }
+
+ /**
+ * Return list of strings with valid option values which used for testing
+ * using jcmd, attach and etc.
+ *
+ * @return list of strings which contain valid values for option
+ */
+ @Override
+ protected List<String> getValidValues() {
+ List<String> validValues = new ArrayList<>();
+
+ validValues.add(min.toString());
+ validValues.add(max.toString());
+
+ if ((min.compareTo(MINUS_ONE) == -1) && (max.compareTo(MINUS_ONE) == 1)) {
+ /*
+ * Add -1 as valid value if min is less than -1 and max is greater than -1
+ */
+ validValues.add("-1");
+ }
+
+ if ((min.compareTo(BigInteger.ZERO) == -1) && (max.compareTo(BigInteger.ZERO) == 1)) {
+ /*
+ * Add 0 as valid value if min is less than 0 and max is greater than 0
+ */
+ validValues.add("0");
+ }
+ if ((min.compareTo(BigInteger.ONE) == -1) && (max.compareTo(BigInteger.ONE) == 1)) {
+ /*
+ * Add 1 as valid value if min is less than 1 and max is greater than 1
+ */
+ validValues.add("1");
+ }
+
+ if (max.compareTo(MAX_4_BYTE_INT_PLUS_ONE) == 1) {
+ /*
+ * Check for overflow when flag is assigned to the
+ * 4 byte int variable
+ */
+ validValues.add(MAX_4_BYTE_INT_PLUS_ONE.toString());
+ }
+
+ if (max.compareTo(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE) == 1) {
+ /*
+ * Check for overflow when flag is assigned to the
+ * 4 byte unsigned int variable
+ */
+ validValues.add(MAX_4_BYTE_UNSIGNED_INT_PLUS_ONE.toString());
+ }
+
+ return validValues;
+ }
+
+ /**
+ * Return list of strings with invalid option values which used for testing
+ * using jcmd, attach and etc.
+ *
+ * @return list of strings which contain invalid values for option
+ */
+ @Override
+ protected List<String> getInvalidValues() {
+ List<String> invalidValues = new ArrayList<>();
+
+ if (withRange) {
+ /* Return invalid values only for options which have defined range in VM */
+ if ((is32Bit && min.compareTo(MIN_4_BYTE_INT) != 0)
+ || (!is32Bit && min.compareTo(MIN_LONG) != 0)) {
+ invalidValues.add(min.subtract(BigInteger.ONE).toString());
+ }
+
+ if (!unsigned
+ && ((is32Bit && (max.compareTo(MAX_4_BYTE_INT) != 0))
+ || (!is32Bit && (max.compareTo(MAX_LONG) != 0)))) {
+ invalidValues.add(max.add(BigInteger.ONE).toString());
+ }
+
+ if (unsigned
+ && ((is32Bit && (max.compareTo(MAX_4_BYTE_UNSIGNED_INT) != 0))
+ || (!is32Bit && !uint64 && (max.compareTo(MAX_UNSIGNED_LONG) != 0))
+ || (uint64 && (max.compareTo(MAX_UNSIGNED_LONG_64) != 0)))) {
+ invalidValues.add(max.add(BigInteger.ONE).toString());
+ }
+ }
+
+ return invalidValues;
+ }
+
+ /**
+ * Return expected error message for option with value "value" when it used
+ * on command line with passed value
+ *
+ * @param value Option value
+ * @return expected error message
+ */
+ @Override
+ protected String getErrorMessageCommandLine(String value) {
+ String errorMsg;
+
+ if (withRange) {
+ /* Option have defined range in VM */
+ if (unsigned && ((new BigInteger(value)).compareTo(BigInteger.ZERO) < 0)) {
+ /*
+ * Special case for unsigned options with lower range equal to 0. If
+ * passed value is negative then error will be caught earlier for
+ * such options. Thus use different error message.
+ */
+ errorMsg = String.format("Improperly specified VM option '%s=%s'", name, value);
+ } else {
+ errorMsg = String.format("%s %s=%s is outside the allowed range [ %s ... %s ]",
+ type, name, value, min.toString(), max.toString());
+ }
+ } else {
+ errorMsg = "";
+ }
+
+ return errorMsg;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOption.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package optionsvalidation;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.AttachOperationFailedException;
+import java.util.ArrayList;
+import java.util.List;
+import jdk.test.lib.DynamicVMOption;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.dcmd.CommandExecutor;
+import jdk.test.lib.dcmd.JMXExecutor;
+import sun.tools.attach.HotSpotVirtualMachine;
+
+import static optionsvalidation.JVMOptionsUtils.failedMessage;
+import static optionsvalidation.JVMOptionsUtils.printOutputContent;
+import static optionsvalidation.JVMOptionsUtils.VMType;
+
+public abstract class JVMOption {
+
+ /**
+ * Executor for JCMD
+ */
+ private final static CommandExecutor executor = new JMXExecutor();
+
+ /**
+ * Name of the tested parameter
+ */
+ protected String name;
+
+ /**
+ * Range is defined for option inside VM
+ */
+ protected boolean withRange;
+
+ /**
+ * Prepend string which added before testing option to the command line
+ */
+ private final List<String> prepend;
+ private final StringBuilder prependString;
+
+ protected JVMOption() {
+ this.prepend = new ArrayList<>();
+ prependString = new StringBuilder();
+ withRange = false;
+ }
+
+ /**
+ * Create JVM Option with given type and name.
+ *
+ * @param type type: "intx", "size_t", "uintx", "uint64_t" or "double"
+ * @param name name of the option
+ * @return created JVMOption
+ */
+ static JVMOption createVMOption(String type, String name) {
+ JVMOption parameter;
+
+ switch (type) {
+ case "int":
+ case "intx":
+ case "size_t":
+ case "uint":
+ case "uintx":
+ case "uint64_t":
+ parameter = new IntJVMOption(name, type);
+ break;
+ case "double":
+ parameter = new DoubleJVMOption(name);
+ break;
+ default:
+ throw new Error("Expected only \"int\", \"intx\", \"size_t\", "
+ + "\"uint\", \"uintx\", \"uint64_t\", or \"double\" "
+ + "option types! Got " + type + " type!");
+ }
+
+ return parameter;
+ }
+
+ /**
+ * Add passed options to the prepend options of the option. Prepend options
+ * will be added before testing option to the command line.
+ *
+ * @param options array of prepend options
+ */
+ public final void addPrepend(String... options) {
+ String toAdd;
+
+ for (String option : options) {
+ if (option.startsWith("-")) {
+ toAdd = option;
+ } else {
+ /* Add "-" before parameter name */
+ toAdd = "-" + option;
+
+ }
+ prepend.add(toAdd);
+ prependString.append(toAdd).append(" ");
+ }
+ }
+
+ /**
+ * Get name of the option
+ *
+ * @return name of the option
+ */
+ final String getName() {
+ return name;
+ }
+
+ /**
+ * Mark this option as option which range is defined inside VM
+ */
+ final void optionWithRange() {
+ withRange = true;
+ }
+
+ /**
+ * Set new minimum option value
+ *
+ * @param min new minimum value
+ */
+ abstract void setMin(String min);
+
+ /**
+ * Get string with minimum value of the option
+ *
+ * @return string with minimum value of the option
+ */
+ abstract String getMin();
+
+ /**
+ * Set new maximum option value
+ *
+ * @param max new maximum value
+ */
+ abstract void setMax(String min);
+
+ /**
+ * Get string with maximum value of the option
+ *
+ * @return string with maximum value of the option
+ */
+ abstract String getMax();
+
+ /**
+ * Return list of strings with valid option values which used for testing
+ * using jcmd, attach and etc.
+ *
+ * @return list of strings which contain valid values for option
+ */
+ protected abstract List<String> getValidValues();
+
+ /**
+ * Return list of strings with invalid option values which used for testing
+ * using jcmd, attach and etc.
+ *
+ * @return list of strings which contain invalid values for option
+ */
+ protected abstract List<String> getInvalidValues();
+
+ /**
+ * Return expected error message for option with value "value" when it used
+ * on command line with passed value
+ *
+ * @param value option value
+ * @return expected error message
+ */
+ protected abstract String getErrorMessageCommandLine(String value);
+
+ /**
+ * Testing writeable option using DynamicVMOption isValidValue and
+ * isInvalidValue methods
+ *
+ * @return number of failed tests
+ */
+ public int testDynamic() {
+ DynamicVMOption option = new DynamicVMOption(name);
+ int failedTests = 0;
+ String origValue;
+
+ if (option.isWriteable()) {
+
+ System.out.println("Testing " + name + " option dynamically by DynamicVMOption");
+
+ origValue = option.getValue();
+
+ for (String value : getValidValues()) {
+ if (!option.isValidValue(value)) {
+ failedMessage(String.format("Option %s: Valid value \"%s\" is invalid", name, value));
+ failedTests++;
+ }
+ }
+
+ for (String value : getInvalidValues()) {
+ if (option.isValidValue(value)) {
+ failedMessage(String.format("Option %s: Invalid value \"%s\" is valid", name, value));
+ failedTests++;
+ }
+ }
+
+ option.setValue(origValue);
+ }
+
+ return failedTests;
+ }
+
+ /**
+ * Testing writeable option using Jcmd
+ *
+ * @return number of failed tests
+ */
+ public int testJcmd() {
+ DynamicVMOption option = new DynamicVMOption(name);
+ int failedTests = 0;
+ OutputAnalyzer out;
+ String origValue;
+
+ if (option.isWriteable()) {
+
+ System.out.println("Testing " + name + " option dynamically by jcmd");
+
+ origValue = option.getValue();
+
+ for (String value : getValidValues()) {
+ out = executor.execute(String.format("VM.set_flag %s %s", name, value), true);
+
+ if (out.getOutput().contains(name + " error")) {
+ failedMessage(String.format("Option %s: Can not change "
+ + "option to valid value \"%s\" via jcmd", name, value));
+ printOutputContent(out);
+ failedTests++;
+ }
+ }
+
+ for (String value : getInvalidValues()) {
+ out = executor.execute(String.format("VM.set_flag %s %s", name, value), true);
+
+ if (!out.getOutput().contains(name + " error")) {
+ failedMessage(String.format("Option %s: Error not reported for "
+ + "option when it chagned to invalid value \"%s\" via jcmd", name, value));
+ printOutputContent(out);
+ failedTests++;
+ }
+ }
+
+ option.setValue(origValue);
+ }
+
+ return failedTests;
+ }
+
+ private boolean setFlagAttach(HotSpotVirtualMachine vm, String flagName, String flagValue) throws Exception {
+ boolean result;
+
+ try {
+ vm.setFlag(flagName, flagValue);
+ result = true;
+ } catch (AttachOperationFailedException e) {
+ result = false;
+ }
+
+ return result;
+ }
+
+ /**
+ * Testing writeable option using attach method
+ *
+ * @return number of failed tests
+ * @throws Exception if an error occurred while attaching to the target JVM
+ */
+ public int testAttach() throws Exception {
+ DynamicVMOption option = new DynamicVMOption(name);
+ int failedTests = 0;
+ String origValue;
+
+ if (option.isWriteable()) {
+
+ System.out.println("Testing " + name + " option dynamically via attach");
+
+ origValue = option.getValue();
+
+ HotSpotVirtualMachine vm = (HotSpotVirtualMachine) VirtualMachine.attach(String.valueOf(ProcessTools.getProcessId()));
+
+ for (String value : getValidValues()) {
+ if (!setFlagAttach(vm, name, value)) {
+ failedMessage(String.format("Option %s: Can not change option to valid value \"%s\" via attach", name, value));
+ failedTests++;
+ }
+ }
+
+ for (String value : getInvalidValues()) {
+ if (setFlagAttach(vm, name, value)) {
+ failedMessage(String.format("Option %s: Option changed to invalid value \"%s\" via attach", name, value));
+ failedTests++;
+ }
+ }
+
+ vm.detach();
+
+ option.setValue(origValue);
+ }
+
+ return failedTests;
+ }
+
+ /**
+ * Run java with passed parameter and check the result depending on the
+ * 'valid' parameter
+ *
+ * @param param tested parameter passed to the JVM
+ * @param valid indicates whether the JVM should fail or not
+ * @return true - if test passed
+ * @throws Exception if java process can not be started
+ */
+ private boolean runJavaWithParam(String optionValue, boolean valid) throws Exception {
+ int exitCode;
+ boolean result = true;
+ String value = optionValue.substring(optionValue.lastIndexOf("=") + 1);
+ String fullOptionString = prependString.toString() + optionValue;
+ List<String> runJava = new ArrayList<>();
+ OutputAnalyzer out;
+
+ if (VMType != null) {
+ runJava.add(VMType);
+ }
+ runJava.addAll(prepend);
+ runJava.add(optionValue);
+ runJava.add(JVMOptionsUtils.class.getName());
+
+ out = new OutputAnalyzer(ProcessTools.createJavaProcessBuilder(runJava.toArray(new String[0])).start());
+
+ exitCode = out.getExitValue();
+
+ if (out.getOutput().contains("A fatal error has been detected by the Java Runtime Environment")) {
+ /* Always consider "fatal error" in output as fail */
+ failedMessage(name, fullOptionString, valid, "JVM output reports a fatal error. JVM exited with code " + exitCode + "!");
+ printOutputContent(out);
+ result = false;
+ } else if (valid == true) {
+ if ((exitCode != 0) && (exitCode != 1)) {
+ failedMessage(name, fullOptionString, valid, "JVM exited with unexpected error code = " + exitCode);
+ printOutputContent(out);
+ result = false;
+ } else if ((exitCode == 1) && (out.getOutput().isEmpty() == true)) {
+ failedMessage(name, fullOptionString, valid, "JVM exited with error(exitcode == 1)"
+ + ", but with empty stdout and stderr. Description of error is needed!");
+ result = false;
+ } else if (out.getOutput().contains("is outside the allowed range")) {
+ failedMessage(name, fullOptionString, valid, "JVM output contains \"is outside the allowed range\"");
+ printOutputContent(out);
+ result = false;
+ }
+ } else {
+ // valid == false
+ if (exitCode == 0) {
+ failedMessage(name, fullOptionString, valid, "JVM successfully exit");
+ result = false;
+ } else if (exitCode != 1) {
+ failedMessage(name, fullOptionString, valid, "JVM exited with code "
+ + exitCode + " which not equal to 1");
+ result = false;
+ } else if (!out.getOutput().contains(getErrorMessageCommandLine(value))) {
+ failedMessage(name, fullOptionString, valid, "JVM output does not contain "
+ + "expected output \"" + getErrorMessageCommandLine(value) + "\"");
+ printOutputContent(out);
+ result = false;
+ }
+ }
+
+ System.out.println("");
+
+ return result;
+ }
+
+ /**
+ * Construct option string with passed value
+ *
+ * @param value parameter value
+ * @return string containing option with passed value
+ */
+ private String constructOption(String value) {
+ return "-XX:" + name + "=" + value;
+ }
+
+ /**
+ * Return list of strings which contain options with valid values which can
+ * be used for testing on command line
+ *
+ * @return list of strings which contain options with valid values
+ */
+ private List<String> getValidCommandLineOptions() {
+ List<String> validParameters = new ArrayList<>();
+
+ for (String value : getValidValues()) {
+ validParameters.add(constructOption(value));
+ }
+
+ return validParameters;
+ }
+
+ /**
+ * Return list of strings which contain options with invalid values which
+ * can be used for testing on command line
+ *
+ * @return list of strings which contain options with invalid values
+ */
+ private List<String> getInvalidCommandLineOptions() {
+ List<String> invalidParameters = new ArrayList<>();
+
+ for (String value : getInvalidValues()) {
+ invalidParameters.add(constructOption(value));
+ }
+
+ return invalidParameters;
+ }
+
+ /**
+ * Perform test of the parameter. Call java with valid option values and
+ * with invalid option values.
+ *
+ * @return number of failed tests
+ * @throws Exception if java process can not be started
+ */
+ public int testCommandLine() throws Exception {
+ ProcessBuilder pb;
+ int failed = 0;
+ List<String> optionValuesList;
+
+ optionValuesList = getValidCommandLineOptions();
+
+ if (optionValuesList.isEmpty() != true) {
+ System.out.println("Testing valid " + name + " values.");
+ for (String optionValid : optionValuesList) {
+ if (runJavaWithParam(optionValid, true) == false) {
+ failed++;
+ }
+ }
+ }
+
+ optionValuesList = getInvalidCommandLineOptions();
+
+ if (optionValuesList.isEmpty() != true) {
+ System.out.println("Testing invalid " + name + " values.");
+
+ for (String optionInvalid : optionValuesList) {
+ if (runJavaWithParam(optionInvalid, false) == false) {
+ failed++;
+ }
+ }
+ }
+
+ /* return number of failed tests for this option */
+ return failed;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package optionsvalidation;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.function.Predicate;
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.Platform;
+import jdk.test.lib.ProcessTools;
+
+public class JVMOptionsUtils {
+
+ /* Java option which print options with ranges */
+ private static final String PRINT_FLAGS_RANGES = "-XX:+PrintFlagsRanges";
+
+ /* StringBuilder to accumulate failed message */
+ private static final StringBuilder finalFailedMessage = new StringBuilder();
+
+ /* Used to start the JVM with the same type as current */
+ static String VMType;
+
+ static {
+ if (Platform.isServer()) {
+ VMType = "-server";
+ } else if (Platform.isClient()) {
+ VMType = "-client";
+ } else if (Platform.isMinimal()) {
+ VMType = "-minimal";
+ } else if (Platform.isGraal()) {
+ VMType = "-graal";
+ } else {
+ VMType = null;
+ }
+ }
+
+ /**
+ * Add dependency for option depending on it's name. E.g. enable G1 GC for
+ * G1 options or add prepend options to not hit constraints.
+ *
+ * @param option option
+ */
+ private static void addNameDependency(JVMOption option) {
+ String name = option.getName();
+
+ if (name.startsWith("G1")) {
+ option.addPrepend("-XX:+UseG1GC");
+ }
+
+ if (name.startsWith("CMS")) {
+ option.addPrepend("-XX:+UseConcMarkSweepGC");
+ }
+
+ switch (name) {
+ case "MinHeapFreeRatio":
+ option.addPrepend("-XX:MaxHeapFreeRatio=100");
+ break;
+ case "MaxHeapFreeRatio":
+ option.addPrepend("-XX:MinHeapFreeRatio=0");
+ break;
+ case "MinMetaspaceFreeRatio":
+ option.addPrepend("-XX:MaxMetaspaceFreeRatio=100");
+ break;
+ case "MaxMetaspaceFreeRatio":
+ option.addPrepend("-XX:MinMetaspaceFreeRatio=0");
+ break;
+ case "CMSOldPLABMin":
+ option.addPrepend("-XX:CMSOldPLABMax=" + option.getMax());
+ break;
+ case "CMSOldPLABMax":
+ option.addPrepend("-XX:CMSOldPLABMin=" + option.getMin());
+ break;
+ case "CMSPrecleanNumerator":
+ option.addPrepend("-XX:CMSPrecleanDenominator=" + option.getMax());
+ break;
+ case "CMSPrecleanDenominator":
+ option.addPrepend("-XX:CMSPrecleanNumerator=" + ((new Integer(option.getMin())) - 1));
+ break;
+ case "InitialTenuringThreshold":
+ option.addPrepend("-XX:MaxTenuringThreshold=" + option.getMax());
+ break;
+ default:
+ /* Do nothing */
+ break;
+ }
+
+ }
+
+ /**
+ * Add dependency for option depending on it's type. E.g. run the JVM in
+ * compilation mode for compiler options.
+ *
+ * @param option option
+ * @param type type of the option
+ */
+ private static void addTypeDependency(JVMOption option, String type) {
+ if (type.contains("C1") || type.contains("C2")) {
+ /* Run in compiler mode for compiler flags */
+ option.addPrepend("-Xcomp");
+ }
+ }
+
+ /**
+ * Parse JVM Options. Get input from "inputReader". Parse using
+ * "-XX:+PrintFlagsRanges" output format.
+ *
+ * @param inputReader input data for parsing
+ * @param withRanges true if needed options with defined ranges inside JVM
+ * @param acceptOrigin predicate for option origins. Origins can be
+ * "product", "diagnostic" etc. Accept option only if acceptOrigin evaluates
+ * to true.
+ * @return map from option name to the JVMOption object
+ * @throws IOException if an error occurred while reading the data
+ */
+ private static Map<String, JVMOption> getJVMOptions(Reader inputReader,
+ boolean withRanges, Predicate<String> acceptOrigin) throws IOException {
+ BufferedReader reader = new BufferedReader(inputReader);
+ String type;
+ String line;
+ String token;
+ String name;
+ StringTokenizer st;
+ JVMOption option;
+ Map<String, JVMOption> allOptions = new LinkedHashMap<>();
+
+ // Skip first line
+ line = reader.readLine();
+
+ while ((line = reader.readLine()) != null) {
+ /*
+ * Parse option from following line:
+ * <type> <name> [ <min, optional> ... <max, optional> ] {<origin>}
+ */
+ st = new StringTokenizer(line);
+
+ type = st.nextToken();
+
+ name = st.nextToken();
+
+ option = JVMOption.createVMOption(type, name);
+
+ /* Skip '[' */
+ token = st.nextToken();
+
+ /* Read min range or "..." if range is absent */
+ token = st.nextToken();
+
+ if (token.equals("...") == false) {
+ if (!withRanges) {
+ /*
+ * Option have range, but asked for options without
+ * ranges => skip it
+ */
+ continue;
+ }
+
+ /* Mark this option as option which range is defined in VM */
+ option.optionWithRange();
+
+ option.setMin(token);
+
+ /* Read "..." and skip it */
+ token = st.nextToken();
+
+ /* Get max value */
+ token = st.nextToken();
+ option.setMax(token);
+ } else if (withRanges) {
+ /*
+ * Option not have range, but asked for options with
+ * ranges => skip it
+ */
+ continue;
+ }
+
+ /* Skip ']' */
+ token = st.nextToken();
+
+ /* Read origin of the option */
+ token = st.nextToken();
+
+ while (st.hasMoreTokens()) {
+ token += st.nextToken();
+ };
+ token = token.substring(1, token.indexOf("}"));
+
+ if (acceptOrigin.test(token)) {
+ addTypeDependency(option, token);
+ addNameDependency(option);
+
+ allOptions.put(name, option);
+ }
+ }
+
+ return allOptions;
+ }
+
+ static void failedMessage(String optionName, String value, boolean valid, String message) {
+ String temp;
+
+ if (valid) {
+ temp = "valid";
+ } else {
+ temp = "invalid";
+ }
+
+ failedMessage(String.format("Error processing option %s with %s value '%s'! %s",
+ optionName, temp, value, message));
+ }
+
+ static void failedMessage(String message) {
+ System.err.println("TEST FAILED: " + message);
+ finalFailedMessage.append(String.format("(%s)%n", message));
+ }
+
+ static void printOutputContent(OutputAnalyzer output) {
+ System.err.println(String.format("stdout content[%s]", output.getStdout()));
+ System.err.println(String.format("stderr content[%s]%n", output.getStderr()));
+ }
+
+ /**
+ * Return string with accumulated failure messages
+ *
+ * @return string with accumulated failure messages
+ */
+ public static String getMessageWithFailures() {
+ return finalFailedMessage.toString();
+ }
+
+ /**
+ * Run command line tests for options passed in the list
+ *
+ * @param options list of options to test
+ * @return number of failed tests
+ * @throws Exception if java process can not be started
+ */
+ public static int runCommandLineTests(List<? extends JVMOption> options) throws Exception {
+ int failed = 0;
+
+ for (JVMOption option : options) {
+ failed += option.testCommandLine();
+ }
+
+ return failed;
+ }
+
+ /**
+ * Test passed options using DynamicVMOption isValidValue and isInvalidValue
+ * methods. Only tests writeable options.
+ *
+ * @param options list of options to test
+ * @return number of failed tests
+ */
+ public static int runDynamicTests(List<? extends JVMOption> options) {
+ int failed = 0;
+
+ for (JVMOption option : options) {
+ failed += option.testDynamic();
+ }
+
+ return failed;
+ }
+
+ /**
+ * Test passed options using Jcmd. Only tests writeable options.
+ *
+ * @param options list of options to test
+ * @return number of failed tests
+ */
+ public static int runJcmdTests(List<? extends JVMOption> options) {
+ int failed = 0;
+
+ for (JVMOption option : options) {
+ failed += option.testJcmd();
+ }
+
+ return failed;
+ }
+
+ /**
+ * Test passed option using attach method. Only tests writeable options.
+ *
+ * @param options list of options to test
+ * @return number of failed tests
+ * @throws Exception if an error occurred while attaching to the target JVM
+ */
+ public static int runAttachTests(List<? extends JVMOption> options) throws Exception {
+ int failed = 0;
+
+ for (JVMOption option : options) {
+ failed += option.testAttach();
+ }
+
+ return failed;
+ }
+
+ /**
+ * Get JVM options as map. Can return options with defined ranges or options
+ * without range depending on "withRanges" argument. "acceptOrigin"
+ * predicate can be used to filter option origin.
+ *
+ * @param withRanges true if needed options with defined ranges inside JVM
+ * @param acceptOrigin predicate for option origins. Origins can be
+ * "product", "diagnostic" etc. Accept option only if acceptOrigin evaluates
+ * to true.
+ * @param additionalArgs additional arguments to the Java process which ran
+ * with "-XX:+PrintFlagsRanges"
+ * @return map from option name to the JVMOption object
+ * @throws Exception if a new process can not be created or an error
+ * occurred while reading the data
+ */
+ public static Map<String, JVMOption> getOptionsAsMap(boolean withRanges, Predicate<String> acceptOrigin,
+ String... additionalArgs) throws Exception {
+ Map<String, JVMOption> result;
+ Process p;
+ List<String> runJava = new ArrayList<>();
+
+ if (additionalArgs.length > 0) {
+ runJava.addAll(Arrays.asList(additionalArgs));
+ }
+
+ if (VMType != null) {
+ runJava.add(VMType);
+ }
+ runJava.add(PRINT_FLAGS_RANGES);
+ runJava.add("-version");
+
+ p = ProcessTools.createJavaProcessBuilder(runJava.toArray(new String[0])).start();
+
+ result = getJVMOptions(new InputStreamReader(p.getInputStream()), withRanges, acceptOrigin);
+
+ p.waitFor();
+
+ return result;
+ }
+
+ /**
+ * Get JVM options as list. Can return options with defined ranges or
+ * options without range depending on "withRanges" argument. "acceptOrigin"
+ * predicate can be used to filter option origin.
+ *
+ * @param withRanges true if needed options with defined ranges inside JVM
+ * @param acceptOrigin predicate for option origins. Origins can be
+ * "product", "diagnostic" etc. Accept option only if acceptOrigin evaluates
+ * to true.
+ * @param additionalArgs additional arguments to the Java process which ran
+ * with "-XX:+PrintFlagsRanges"
+ * @return List of options
+ * @throws Exception if a new process can not be created or an error
+ * occurred while reading the data
+ */
+ public static List<JVMOption> getOptions(boolean withRanges, Predicate<String> acceptOrigin,
+ String... additionalArgs) throws Exception {
+ return new ArrayList<>(getOptionsAsMap(withRanges, acceptOrigin, additionalArgs).values());
+ }
+
+ /**
+ * Get JVM options with ranges as list. "acceptOrigin" predicate can be used
+ * to filter option origin.
+ *
+ * @param acceptOrigin predicate for option origins. Origins can be
+ * "product", "diagnostic" etc. Accept option only if acceptOrigin evaluates
+ * to true.
+ * @param additionalArgs additional arguments to the Java process which ran
+ * with "-XX:+PrintFlagsRanges"
+ * @return List of options
+ * @throws Exception if a new process can not be created or an error
+ * occurred while reading the data
+ */
+ public static List<JVMOption> getOptionsWithRange(Predicate<String> acceptOrigin, String... additionalArgs) throws Exception {
+ return getOptions(true, acceptOrigin, additionalArgs);
+ }
+
+ /**
+ * Get JVM options with ranges as list.
+ *
+ * @param additionalArgs additional arguments to the Java process which ran
+ * with "-XX:+PrintFlagsRanges"
+ * @return list of options
+ * @throws Exception if a new process can not be created or an error
+ * occurred while reading the data
+ */
+ public static List<JVMOption> getOptionsWithRange(String... additionalArgs) throws Exception {
+ return getOptionsWithRange(origin -> true, additionalArgs);
+ }
+
+ /**
+ * Get JVM options with range as map. "acceptOrigin" predicate can be used
+ * to filter option origin.
+ *
+ * @param acceptOrigin predicate for option origins. Origins can be
+ * "product", "diagnostic" etc. Accept option only if acceptOrigin evaluates
+ * to true.
+ * @param additionalArgs additional arguments to the Java process which ran
+ * with "-XX:+PrintFlagsRanges"
+ * @return Map from option name to the JVMOption object
+ * @throws Exception if a new process can not be created or an error
+ * occurred while reading the data
+ */
+ public static Map<String, JVMOption> getOptionsWithRangeAsMap(Predicate<String> acceptOrigin, String... additionalArgs) throws Exception {
+ return getOptionsAsMap(true, acceptOrigin, additionalArgs);
+ }
+
+ /**
+ * Get JVM options with range as map
+ *
+ * @param additionalArgs additional arguments to the Java process which ran
+ * with "-XX:+PrintFlagsRanges"
+ * @return map from option name to the JVMOption object
+ * @throws Exception if a new process can not be created or an error
+ * occurred while reading the data
+ */
+ public static Map<String, JVMOption> getOptionsWithRangeAsMap(String... additionalArgs) throws Exception {
+ return getOptionsWithRangeAsMap(origin -> true, additionalArgs);
+ }
+
+ /* Simple method to test that java start-up. Used for testing options. */
+ public static void main(String[] args) {
+ System.out.print("Java start-up!");
+ }
+}
--- a/hotspot/test/runtime/CompressedOops/CompressedClassSpaceSize.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/runtime/CompressedOops/CompressedClassSpaceSize.java Thu Jun 25 09:48:50 2015 -0700
@@ -42,7 +42,7 @@
pb = ProcessTools.createJavaProcessBuilder("-XX:CompressedClassSpaceSize=0",
"-version");
output = new OutputAnalyzer(pb.start());
- output.shouldContain("CompressedClassSpaceSize of 0 is invalid")
+ output.shouldContain("outside the allowed range")
.shouldHaveExitValue(1);
// Invalid size of -1 should be handled correctly
@@ -57,7 +57,7 @@
pb = ProcessTools.createJavaProcessBuilder("-XX:CompressedClassSpaceSize=4g",
"-version");
output = new OutputAnalyzer(pb.start());
- output.shouldContain("CompressedClassSpaceSize of 4294967296 is invalid")
+ output.shouldContain("outside the allowed range")
.shouldHaveExitValue(1);
--- a/hotspot/test/runtime/CompressedOops/ObjectAlignment.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/runtime/CompressedOops/ObjectAlignment.java Thu Jun 25 09:48:50 2015 -0700
@@ -39,21 +39,22 @@
if (Platform.is64bit()) {
// Minimum alignment should be 8
testObjectAlignment(4)
- .shouldContain("error: ObjectAlignmentInBytes=4 must be greater or equal 8")
+ .shouldContain("outside the allowed range")
.shouldHaveExitValue(1);
// Alignment has to be a power of 2
testObjectAlignment(9)
- .shouldContain("error: ObjectAlignmentInBytes=9 must be power of 2")
+ .shouldContain("must be power of 2")
.shouldHaveExitValue(1);
testObjectAlignment(-1)
- .shouldContain("error: ObjectAlignmentInBytes=-1 must be power of 2")
+ .shouldContain("must be power of 2")
+ .shouldContain("outside the allowed range")
.shouldHaveExitValue(1);
// Maximum alignment allowed is 256
testObjectAlignment(512)
- .shouldContain("error: ObjectAlignmentInBytes=512 must not be greater than 256")
+ .shouldContain("outside the allowed range")
.shouldHaveExitValue(1);
// Valid alignments should work
@@ -74,4 +75,4 @@
"-version");
return new OutputAnalyzer(pb.start());
}
-}
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/RedefineTests/RedefineRunningMethodsWithResolutionErrors.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8076110
+ * @summary Redefine running methods that have cached resolution errors
+ * @library /testlibrary
+ * @modules java.instrument
+ * java.base/jdk.internal.org.objectweb.asm
+ * @build RedefineClassHelper
+ * @run main RedefineClassHelper
+ * @run main/othervm -javaagent:redefineagent.jar -XX:TraceRedefineClasses=0x600 RedefineRunningMethodsWithResolutionErrors
+ */
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+
+import java.lang.reflect.InvocationTargetException;
+
+public class RedefineRunningMethodsWithResolutionErrors extends ClassLoader implements Opcodes {
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.equals("C")) {
+ byte[] b = loadC(false);
+ return defineClass(name, b, 0, b.length);
+ } else {
+ return super.findClass(name);
+ }
+ }
+
+ private static byte[] loadC(boolean redefine) {
+ ClassWriter cw = new ClassWriter(0);
+
+ cw.visit(52, ACC_SUPER | ACC_PUBLIC, "C", null, "java/lang/Object", null);
+ {
+ MethodVisitor mv;
+
+ mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m", "()V", null, null);
+ mv.visitCode();
+
+ // First time we run we will:
+ // 1) Cache resolution errors
+ // 2) Redefine the class / method
+ // 3) Try to read the resolution errors that were cached
+ //
+ // The redefined method will never run, throw error to be sure
+ if (redefine) {
+ createThrowRuntimeExceptionCode(mv, "The redefined method was called");
+ } else {
+ createMethodBody(mv);
+ }
+ mv.visitMaxs(3, 0);
+ mv.visitEnd();
+ }
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+
+ private static void createMethodBody(MethodVisitor mv) {
+ Label classExists = new Label();
+
+ // Cache resolution errors
+ createLoadNonExistentClassCode(mv, classExists);
+
+ // Redefine our own class and method
+ mv.visitMethodInsn(INVOKESTATIC, "RedefineRunningMethodsWithResolutionErrors", "redefine", "()V");
+
+ // Provoke the same error again to make sure the resolution error cache works
+ createLoadNonExistentClassCode(mv, classExists);
+
+ // Test passed
+ mv.visitInsn(RETURN);
+
+ mv.visitFrame(F_SAME, 0, new Object[0], 0, new Object[0]);
+ mv.visitLabel(classExists);
+
+ createThrowRuntimeExceptionCode(mv, "Loaded class that shouldn't exist (\"NonExistentClass\")");
+ }
+
+ private static void createLoadNonExistentClassCode(MethodVisitor mv, Label classExists) {
+ Label tryLoadBegin = new Label();
+ Label tryLoadEnd = new Label();
+ Label catchLoadBlock = new Label();
+ mv.visitTryCatchBlock(tryLoadBegin, tryLoadEnd, catchLoadBlock, "java/lang/NoClassDefFoundError");
+
+ // Try to load a class that does not exist to provoke resolution errors
+ mv.visitLabel(tryLoadBegin);
+ mv.visitMethodInsn(INVOKESTATIC, "NonExistentClass", "nonExistentMethod", "()V");
+ mv.visitLabel(tryLoadEnd);
+
+ // No NoClassDefFoundError means NonExistentClass existed, which shouldn't happen
+ mv.visitJumpInsn(GOTO, classExists);
+
+ mv.visitFrame(F_SAME1, 0, new Object[0], 1, new Object[] { "java/lang/NoClassDefFoundError" });
+ mv.visitLabel(catchLoadBlock);
+
+ // Ignore the expected NoClassDefFoundError
+ mv.visitInsn(POP);
+ }
+
+ private static void createThrowRuntimeExceptionCode(MethodVisitor mv, String msg) {
+ mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+ mv.visitInsn(DUP);
+ mv.visitLdcInsn(msg);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/String;)V");
+ mv.visitInsn(ATHROW);
+ }
+
+ private static Class<?> c;
+
+ public static void redefine() throws Exception {
+ RedefineClassHelper.redefineClass(c, loadC(true));
+ }
+
+ public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ c = Class.forName("C", true, new RedefineRunningMethodsWithResolutionErrors());
+ c.getMethod("m").invoke(null);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/AnnotationTag.java Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 8042041
+ * @summary Fuzzy-ed RuntimeVisibleAnnotations causes assertion
+ * @compile badAnnotTag.jcod
+ * @run main AnnotationTag
+ */
+
+// Test that a bad element_tag in an element_value of a RuntimeVisibileAnnotation
+// attribute is ignored.
+public class AnnotationTag {
+ public static void main(String args[]) throws Throwable {
+
+ System.out.println("Regression test for bug 8042041");
+ try {
+ Class newClass = Class.forName("badAnnotTag");
+ } catch (java.lang.Throwable e) {
+ throw new RuntimeException(
+ "Unexpected exception: " + e.getMessage());
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/badAnnotTag.jcod Thu Jun 25 09:48:50 2015 -0700
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// This class contains a bad element_tag in an element_value structure for a
+// RuntimeVisibleAnnotation at line 91. The bad element tag should be ignored
+// by the class file parser.
+class badAnnotTag {
+ 0xCAFEBABE;
+ 0; // minor version
+ 52; // version
+ [19] { // Constant Pool
+ ; // first element is empty
+ class #16; // #1 at 0x0A
+ class #17; // #2 at 0x0D
+ class #18; // #3 at 0x10
+ Utf8 "value"; // #4 at 0x13
+ Utf8 "()Ljava/lang/String;"; // #5 at 0x1B
+ Utf8 "SourceFile"; // #6 at 0x32
+ Utf8 "badAnnotTag.java"; // #7 at 0x3F
+ Utf8 "RuntimeVisibleAnnotations"; // #8 at 0x50
+ Utf8 "Ljava/lang/annotation/Target;"; // #9 at 0x6C
+ Utf8 "Ljava/lang/annotation/ElementType;"; // #10 at 0x8C
+ Utf8 "TYPE_USE"; // #11 at 0xB1
+ Utf8 "TYPE_PARAMETER"; // #12 at 0xBC
+ Utf8 "Ljava/lang/annotation/Retention;"; // #13 at 0xCD
+ Utf8 "Ljava/lang/annotation/RetentionPolicy;"; // #14 at 0xF0
+ Utf8 "RUNTIME"; // #15 at 0x0119
+ Utf8 "badAnnotTag"; // #16 at 0x0123
+ Utf8 "java/lang/Object"; // #17 at 0x0127
+ Utf8 "java/lang/annotation/Annotation"; // #18 at 0x013A
+ } // Constant Pool
+
+ 0x2600; // access
+ #1;// this_cpx
+ #2;// super_cpx
+
+ [1] { // Interfaces
+ #3;
+ } // Interfaces
+
+ [0] { // fields
+ } // fields
+
+ [1] { // methods
+ { // Member at 0x016A
+ 0x0401; // access
+ #4; // name_cpx
+ #5; // sig_cpx
+ [0] { // Attributes
+ } // Attributes
+ } // Member
+ } // methods
+
+ [2] { // Attributes
+ Attr(#6, 2) { // SourceFile at 0x0174
+ #7;
+ } // end SourceFile
+ ;
+ Attr(#8, 32) { // RuntimeVisibleAnnotations at 0x017C
+ [2] { // annotations
+ { // annotation
+ #9;
+ [1] { // element_value_pairs
+ { // element value pair
+ #4;
+ { // element_value
+ '[';
+ [2] { // array_value
+ { // element_value
+ 'd'; // * illegal value *, correct value is 'e'
+ { // enum_const_value
+ #10;
+ #11;
+ } // enum_const_value
+ } // element_value
+ ;
+ { // element_value
+ 'e';
+ { // enum_const_value
+ #10;
+ #12;
+ } // enum_const_value
+ } // element_value
+ } // array_value
+ } // element_value
+ } // element value pair
+ } // element_value_pairs
+ } // annotation
+ ;
+ { // annotation
+ #13;
+ [1] { // element_value_pairs
+ { // element value pair
+ #4;
+ { // element_value
+ 'e';
+ { // enum_const_value
+ #14;
+ #15;
+ } // enum_const_value
+ } // element_value
+ } // element value pair
+ } // element_value_pairs
+ } // annotation
+ }
+ } // end RuntimeVisibleAnnotations
+ } // Attributes
+} // end class badAnnotTag
--- a/hotspot/test/runtime/contended/Options.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/runtime/contended/Options.java Thu Jun 25 09:48:50 2015 -0700
@@ -42,19 +42,19 @@
pb = ProcessTools.createJavaProcessBuilder("-XX:ContendedPaddingWidth=-128", "-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("ContendedPaddingWidth");
- output.shouldContain("must be in between");
+ output.shouldContain("outside the allowed range");
output.shouldHaveExitValue(1);
pb = ProcessTools.createJavaProcessBuilder("-XX:ContendedPaddingWidth=-8", "-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("ContendedPaddingWidth");
- output.shouldContain("must be in between");
+ output.shouldContain("outside the allowed range");
output.shouldHaveExitValue(1);
pb = ProcessTools.createJavaProcessBuilder("-XX:ContendedPaddingWidth=-1", "-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("ContendedPaddingWidth");
- output.shouldContain("must be in between");
+ output.shouldContain("outside the allowed range");
output.shouldContain("must be a multiple of 8");
output.shouldHaveExitValue(1);
@@ -89,17 +89,16 @@
pb = ProcessTools.createJavaProcessBuilder("-XX:ContendedPaddingWidth=8193", "-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("ContendedPaddingWidth");
- output.shouldContain("must be in between");
+ output.shouldContain("outside the allowed range");
output.shouldContain("must be a multiple of 8");
output.shouldHaveExitValue(1);
pb = ProcessTools.createJavaProcessBuilder("-XX:ContendedPaddingWidth=8200", "-version"); // 8192+8 = 8200
output = new OutputAnalyzer(pb.start());
output.shouldContain("ContendedPaddingWidth");
- output.shouldContain("must be in between");
+ output.shouldContain("outside the allowed range");
output.shouldHaveExitValue(1);
}
}
-
--- a/hotspot/test/serviceability/attach/AttachSetGetFlag.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/serviceability/attach/AttachSetGetFlag.java Thu Jun 25 09:48:50 2015 -0700
@@ -61,6 +61,9 @@
// Since it is not manageable, we can't test the setFlag functionality.
testGetFlag("ArrayAllocatorMallocLimit", "128");
// testSetFlag("ArrayAllocatorMallocLimit", "64", "128");
+
+ // Test a uint flag.
+ testGetFlag("ParallelGCThreads", "10");
}
public static ProcessBuilder runTarget(String flagName, String flagValue) throws Exception {
--- a/hotspot/test/serviceability/sa/TestClassLoaderStats.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/serviceability/sa/TestClassLoaderStats.java Thu Jun 25 09:48:50 2015 -0700
@@ -21,9 +21,13 @@
* questions.
*/
+import java.util.ArrayList;
+import java.util.List;
+
import jdk.test.lib.Platform;
import jdk.test.lib.ProcessTools;
import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.Utils;
import jdk.test.lib.apps.LingeredApp;
/*
@@ -44,7 +48,10 @@
LingeredApp app = null;
try {
- app = LingeredApp.startApp();
+ List<String> vmArgs = new ArrayList<String>();
+ vmArgs.add("-XX:+UsePerfData");
+ vmArgs.addAll(Utils.getVmOptions());
+ app = LingeredApp.startApp(vmArgs);
System.out.println("Attaching sun.jvm.hotspot.tools.ClassLoaderStats to " + app.getPid());
ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
@@ -61,7 +68,7 @@
output.stderrShouldNotMatch("[E|e]xception");
output.stderrShouldNotMatch("[E|e]rror");
} finally {
- app.stopApp();
+ LingeredApp.stopApp(app);
}
}
--- a/hotspot/test/serviceability/sa/TestStackTrace.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/serviceability/sa/TestStackTrace.java Thu Jun 25 09:48:50 2015 -0700
@@ -21,9 +21,13 @@
* questions.
*/
+import java.util.ArrayList;
+import java.util.List;
+
import jdk.test.lib.OutputAnalyzer;
import jdk.test.lib.Platform;
import jdk.test.lib.ProcessTools;
+import jdk.test.lib.Utils;
import jdk.test.lib.apps.LingeredApp;
/*
@@ -44,7 +48,10 @@
LingeredApp app = null;
try {
- app = LingeredApp.startApp();
+ List<String> vmArgs = new ArrayList<String>();
+ vmArgs.add("-XX:+UsePerfData");
+ vmArgs.addAll(Utils.getVmOptions());
+ app = LingeredApp.startApp(vmArgs);
System.out.println("Attaching sun.jvm.hotspot.tools.StackTrace to " + app.getPid());
ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
@@ -59,7 +66,7 @@
output.stderrShouldNotMatch("[E|e]xception");
output.stderrShouldNotMatch("[E|e]rror");
} finally {
- app.stopApp();
+ LingeredApp.stopApp(app);
}
}
--- a/hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java Wed Jun 24 09:13:12 2015 +0200
+++ b/hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java Thu Jun 25 09:48:50 2015 -0700
@@ -21,6 +21,13 @@
* questions.
*/
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.OutputBuffer;
+import jdk.test.lib.Platform;
+import jdk.test.lib.ProcessTools;
+
+import java.io.File;
+
/*
* @test
* @bug 8028623
@@ -32,16 +39,8 @@
* jdk.jvmstat/sun.jvmstat.monitor
* @build jdk.test.lib.*
* @compile -encoding utf8 Test8028623.java
- * @run main Test8028623
+ * @run main/othervm -XX:+UsePerfData Test8028623
*/
-
-import jdk.test.lib.JDKToolLauncher;
-import jdk.test.lib.OutputBuffer;
-import jdk.test.lib.Platform;
-import jdk.test.lib.ProcessTools;
-
-import java.io.File;
-
public class Test8028623 {
public static int \u00CB = 1;