--- a/hotspot/agent/make/Makefile Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/agent/make/Makefile Fri Jan 16 12:33:47 2015 -0800
@@ -58,15 +58,19 @@
sun.jvm.hotspot.debugger.dummy \
sun.jvm.hotspot.debugger.linux \
sun.jvm.hotspot.debugger.linux.amd64 \
+sun.jvm.hotspot.debugger.linux.ppc64 \
sun.jvm.hotspot.debugger.linux.x86 \
sun.jvm.hotspot.debugger.posix \
sun.jvm.hotspot.debugger.posix.elf \
+sun.jvm.hotspot.debugger.ppc64 \
sun.jvm.hotspot.debugger.proc \
sun.jvm.hotspot.debugger.proc.amd64 \
+sun.jvm.hotspot.debugger.proc.ppc64 \
sun.jvm.hotspot.debugger.proc.sparc \
sun.jvm.hotspot.debugger.proc.x86 \
sun.jvm.hotspot.debugger.remote \
sun.jvm.hotspot.debugger.remote.amd64 \
+sun.jvm.hotspot.debugger.remote.ppc64 \
sun.jvm.hotspot.debugger.remote.sparc \
sun.jvm.hotspot.debugger.remote.x86 \
sun.jvm.hotspot.debugger.sparc \
@@ -93,9 +97,11 @@
sun.jvm.hotspot.runtime.bsd_x86 \
sun.jvm.hotspot.runtime.linux \
sun.jvm.hotspot.runtime.linux_amd64 \
+sun.jvm.hotspot.runtime.linux_ppc64 \
sun.jvm.hotspot.runtime.linux_sparc \
sun.jvm.hotspot.runtime.linux_x86 \
sun.jvm.hotspot.runtime.posix \
+sun.jvm.hotspot.runtime.ppc64 \
sun.jvm.hotspot.runtime.solaris_amd64 \
sun.jvm.hotspot.runtime.solaris_sparc \
sun.jvm.hotspot.runtime.solaris_x86 \
@@ -142,15 +148,19 @@
sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \
sun/jvm/hotspot/debugger/dummy/*.java \
sun/jvm/hotspot/debugger/linux/*.java \
+sun/jvm/hotspot/debugger/linux/ppc64/*.java \
sun/jvm/hotspot/debugger/linux/x86/*.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/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/ppc64/*.java \
sun/jvm/hotspot/debugger/remote/sparc/*.java \
sun/jvm/hotspot/debugger/remote/x86/*.java \
sun/jvm/hotspot/debugger/sparc/*.java \
@@ -174,9 +184,11 @@
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_ppc64/*.java \
sun/jvm/hotspot/runtime/linux_sparc/*.java \
sun/jvm/hotspot/runtime/linux_x86/*.java \
sun/jvm/hotspot/runtime/posix/*.java \
+sun/jvm/hotspot/runtime/ppc64/*.java \
sun/jvm/hotspot/runtime/solaris_amd64/*.java \
sun/jvm/hotspot/runtime/solaris_sparc/*.java \
sun/jvm/hotspot/runtime/solaris_x86/*.java \
--- a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c Fri Jan 16 12:33:47 2015 -0800
@@ -49,6 +49,10 @@
#include "sun_jvm_hotspot_debugger_sparc_SPARCThreadContext.h"
#endif
+#ifdef ppc64
+#include "sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext.h"
+#endif
+
static jfieldID p_ps_prochandle_ID = 0;
static jfieldID threadList_ID = 0;
static jfieldID loadObjectList_ID = 0;
@@ -341,7 +345,7 @@
return (err == PS_OK)? array : 0;
}
-#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9)
+#if defined(i386) || defined(amd64) || defined(sparc) || defined(sparcv9) | defined(ppc64)
JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0
(JNIEnv *env, jobject this_obj, jint lwp_id) {
@@ -366,6 +370,10 @@
#if defined(sparc) || defined(sparcv9)
#define NPRGREG sun_jvm_hotspot_debugger_sparc_SPARCThreadContext_NPRGREG
#endif
+#ifdef ppc64
+#define NPRGREG sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_NPRGREG
+#endif
+
array = (*env)->NewLongArray(env, NPRGREG);
CHECK_EXCEPTION_(0);
@@ -458,6 +466,45 @@
regs[REG_INDEX(R_O7)] = gregs.u_regs[14];
#endif /* sparc */
+#ifdef ppc64
+#define REG_INDEX(reg) sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_##reg
+
+ regs[REG_INDEX(LR)] = gregs.link;
+ regs[REG_INDEX(NIP)] = gregs.nip;
+ regs[REG_INDEX(R0)] = gregs.gpr[0];
+ regs[REG_INDEX(R1)] = gregs.gpr[1];
+ regs[REG_INDEX(R2)] = gregs.gpr[2];
+ regs[REG_INDEX(R3)] = gregs.gpr[3];
+ regs[REG_INDEX(R4)] = gregs.gpr[4];
+ regs[REG_INDEX(R5)] = gregs.gpr[5];
+ regs[REG_INDEX(R6)] = gregs.gpr[6];
+ regs[REG_INDEX(R7)] = gregs.gpr[7];
+ regs[REG_INDEX(R8)] = gregs.gpr[8];
+ regs[REG_INDEX(R9)] = gregs.gpr[9];
+ regs[REG_INDEX(R10)] = gregs.gpr[10];
+ regs[REG_INDEX(R11)] = gregs.gpr[11];
+ regs[REG_INDEX(R12)] = gregs.gpr[12];
+ regs[REG_INDEX(R13)] = gregs.gpr[13];
+ regs[REG_INDEX(R14)] = gregs.gpr[14];
+ regs[REG_INDEX(R15)] = gregs.gpr[15];
+ regs[REG_INDEX(R16)] = gregs.gpr[16];
+ regs[REG_INDEX(R17)] = gregs.gpr[17];
+ regs[REG_INDEX(R18)] = gregs.gpr[18];
+ regs[REG_INDEX(R19)] = gregs.gpr[19];
+ regs[REG_INDEX(R20)] = gregs.gpr[20];
+ regs[REG_INDEX(R21)] = gregs.gpr[21];
+ regs[REG_INDEX(R22)] = gregs.gpr[22];
+ regs[REG_INDEX(R23)] = gregs.gpr[23];
+ regs[REG_INDEX(R24)] = gregs.gpr[24];
+ regs[REG_INDEX(R25)] = gregs.gpr[25];
+ regs[REG_INDEX(R26)] = gregs.gpr[26];
+ regs[REG_INDEX(R27)] = gregs.gpr[27];
+ regs[REG_INDEX(R28)] = gregs.gpr[28];
+ regs[REG_INDEX(R29)] = gregs.gpr[29];
+ regs[REG_INDEX(R30)] = gregs.gpr[30];
+ regs[REG_INDEX(R31)] = gregs.gpr[31];
+
+#endif
(*env)->ReleaseLongArrayElements(env, array, regs, JNI_COMMIT);
return array;
--- a/hotspot/agent/src/os/linux/symtab.c Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/agent/src/os/linux/symtab.c Fri Jan 16 12:33:47 2015 -0800
@@ -325,6 +325,12 @@
// Reading of elf header
struct elf_section *scn_cache = NULL;
+#if defined(ppc64) && !defined(ABI_ELFv2)
+ // Only big endian ppc64 (i.e. ABI_ELFv1) has 'official procedure descriptors' in ELF files
+ // see: http://refspecs.linuxfoundation.org/LSB_3.1.1/LSB-Core-PPC64/LSB-Core-PPC64/specialsections.html
+ struct elf_section *opd_sect = NULL;
+ ELF_SHDR *opd = NULL;
+#endif
int cnt = 0;
ELF_SHDR* shbuf = NULL;
ELF_SHDR* cursct = NULL;
@@ -368,6 +374,14 @@
cursct++;
}
+#if defined(ppc64) && !defined(ABI_ELFv2)
+ opd_sect = find_section_by_name(".opd", fd, &ehdr, scn_cache);
+ if (opd_sect != NULL && opd_sect->c_data != NULL && opd_sect->c_shdr != NULL) {
+ // plausibility check
+ opd = opd_sect->c_shdr;
+ }
+#endif
+
for (cnt = 1; cnt < ehdr.e_shnum; cnt++) {
ELF_SHDR *shdr = scn_cache[cnt].c_shdr;
@@ -412,6 +426,7 @@
// copy symbols info our symtab and enter them info the hash table
for (j = 0; j < n; j++, syms++) {
ENTRY item, *ret;
+ uintptr_t sym_value;
char *sym_name = symtab->strs + syms->st_name;
// skip non-object and non-function symbols
@@ -422,9 +437,19 @@
if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue;
symtab->symbols[j].name = sym_name;
- symtab->symbols[j].offset = syms->st_value - baseaddr;
symtab->symbols[j].size = syms->st_size;
+ sym_value = syms->st_value;
+#if defined(ppc64) && !defined(ABI_ELFv2)
+ // see hotspot/src/share/vm/utilities/elfFuncDescTable.hpp for a detailed description
+ // of why we have to go this extra way via the '.opd' section on big endian ppc64
+ if (opd != NULL && *sym_name != '.' &&
+ (opd->sh_addr <= sym_value && sym_value <= opd->sh_addr + opd->sh_size)) {
+ sym_value = ((ELF_ADDR*)opd_sect->c_data)[(sym_value - opd->sh_addr) / sizeof(ELF_ADDR*)];
+ }
+#endif
+
+ symtab->symbols[j].offset = sym_value - baseaddr;
item.key = sym_name;
item.data = (void *)&(symtab->symbols[j]);
@@ -433,9 +458,17 @@
}
}
+#if defined(ppc64) && !defined(ABI_ELFv2)
+ // On Linux/PPC64 the debuginfo files contain an empty function descriptor
+ // section (i.e. '.opd' section) which makes the resolution of symbols
+ // with the above algorithm impossible (we would need the have both, the
+ // .opd section from the library and the symbol table from the debuginfo
+ // file which doesn't match with the current workflow.)
+ goto quit;
+#endif
+
// Look for a separate debuginfo file.
if (try_debuginfo) {
-
// We prefer a debug symtab to an object's own symtab, so look in
// the debuginfo file. We stash a copy of the old symtab in case
// there is no debuginfo.
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionPPC64.java Fri Jan 16 12:33:47 2015 -0800
@@ -34,6 +34,6 @@
}
public boolean isBigEndian() {
- return true;
+ return "big".equals(System.getProperty("sun.cpu.endian"));
}
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java Fri Jan 16 12:33:47 2015 -0800
@@ -26,14 +26,17 @@
import java.io.*;
import java.util.*;
+
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.x86.*;
import sun.jvm.hotspot.debugger.amd64.*;
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.utilities.*;
class LinuxCDebugger implements CDebugger {
@@ -96,7 +99,14 @@
Address pc = context.getRegisterAsAddress(SPARCThreadContext.R_O7);
if (pc == null) return null;
return new LinuxSPARCCFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize());
- } else {
+ } else if (cpu.equals("ppc64")) {
+ PPC64ThreadContext context = (PPC64ThreadContext) thread.getContext();
+ Address sp = context.getRegisterAsAddress(PPC64ThreadContext.SP);
+ if (sp == null) return null;
+ Address pc = context.getRegisterAsAddress(PPC64ThreadContext.PC);
+ if (pc == null) return null;
+ return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize());
+ } else {
// Runtime exception thrown by LinuxThreadContextFactory if unknown cpu
ThreadContext context = (ThreadContext) thread.getContext();
return context.getTopFrame(dbg);
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/LinuxThreadContextFactory.java Fri Jan 16 12:33:47 2015 -0800
@@ -29,6 +29,7 @@
import sun.jvm.hotspot.debugger.linux.amd64.*;
import sun.jvm.hotspot.debugger.linux.ia64.*;
import sun.jvm.hotspot.debugger.linux.x86.*;
+import sun.jvm.hotspot.debugger.linux.ppc64.*;
import sun.jvm.hotspot.debugger.linux.sparc.*;
class LinuxThreadContextFactory {
@@ -42,6 +43,8 @@
return new LinuxIA64ThreadContext(dbg);
} else if (cpu.equals("sparc")) {
return new LinuxSPARCThreadContext(dbg);
+ } else if (cpu.equals("ppc64")) {
+ return new LinuxPPC64ThreadContext(dbg);
} else {
try {
Class tcc = Class.forName("sun.jvm.hotspot.debugger.linux." +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64CFrame.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.linux.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.linux.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+import sun.jvm.hotspot.debugger.cdbg.basic.*;
+
+final public class LinuxPPC64CFrame extends BasicCFrame {
+ // package/class internals only
+
+ public LinuxPPC64CFrame(LinuxDebugger dbg, Address sp, Address pc, int address_size) {
+ super(dbg.getCDebugger());
+ this.sp = sp;
+ this.pc = pc;
+ this.dbg = dbg;
+ this.address_size = address_size;
+ }
+
+ // 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 sp;
+ }
+
+ public CFrame sender(ThreadProxy thread) {
+ if (sp == null) {
+ return null;
+ }
+
+ Address nextSP = sp.getAddressAt(0);
+ if (nextSP == null) {
+ return null;
+ }
+ Address nextPC = sp.getAddressAt(2 * address_size);
+ if (nextPC == null) {
+ return null;
+ }
+ return new LinuxPPC64CFrame(dbg, nextSP, nextPC, address_size);
+ }
+
+ public static int PPC64_STACK_BIAS = 0;
+ private static int address_size;
+ private Address pc;
+ private Address sp;
+ private LinuxDebugger dbg;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/linux/ppc64/LinuxPPC64ThreadContext.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.linux.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.linux.*;
+
+public class LinuxPPC64ThreadContext extends PPC64ThreadContext {
+ private LinuxDebugger debugger;
+
+ public LinuxPPC64ThreadContext(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));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/ppc64/PPC64ThreadContext.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+
+/** Specifies the thread context on ppc64 platforms; only a sub-portion
+ * of the context is guaranteed to be present on all operating
+ * systems. */
+
+public abstract class PPC64ThreadContext implements ThreadContext {
+
+ // 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).
+
+ public static final int R31 = 0;
+ public static final int R30 = 1;
+ public static final int R29 = 2;
+ public static final int R28 = 3;
+ public static final int R27 = 4;
+ public static final int R26 = 5;
+ public static final int R25 = 6;
+ public static final int R24 = 7;
+ public static final int R23 = 8;
+ public static final int R22 = 9;
+ public static final int R21 = 10;
+ public static final int R20 = 11;
+ public static final int R19 = 12;
+ public static final int R18 = 13;
+ public static final int R17 = 14;
+ public static final int R16 = 15;
+ public static final int R15 = 16;
+ public static final int R14 = 17;
+ public static final int R13 = 18;
+ public static final int R12 = 19;
+ public static final int R11 = 20;
+ public static final int R10 = 21;
+ public static final int R9 = 22;
+ public static final int R8 = 23;
+ public static final int R7 = 24;
+ public static final int R6 = 25;
+ public static final int R5 = 26;
+ public static final int R4 = 27;
+ public static final int R3 = 28;
+ public static final int R2 = 29;
+ public static final int R1 = 30;
+ public static final int R0 = 31;
+ public static final int NIP = 32;
+ public static final int LR = 33;
+
+ public static final int NPRGREG = 34;
+
+ private static final String[] regNames = {
+ "r31", "r30", "r29", "r28", "r27", "r26", "r25", "r24",
+ "r23", "r22", "r21", "r20", "r19", "r18", "r17", "r16",
+ "r15", "r14", "r13", "r12", "r11", "r10", "r9", "r8",
+ "r7", "r6", "r5", "r4", "r3", "r2", "r1", "r0",
+ "nip", "link"
+ };
+
+ public static final int PC = NIP;
+ public static final int SP = R1;
+
+ private long[] data;
+
+ public PPC64ThreadContext() {
+ data = new long[NPRGREG];
+ }
+
+ public int getNumRegisters() {
+ return NPRGREG;
+ }
+
+ public String getRegisterName(int index) {
+ return regNames[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/proc/ProcDebuggerLocal.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java Fri Jan 16 12:33:47 2015 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,9 @@
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.proc.amd64.*;
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.sparc.*;
import sun.jvm.hotspot.debugger.x86.*;
@@ -86,6 +88,10 @@
threadFactory = new ProcAMD64ThreadFactory(this);
pcRegIndex = AMD64ThreadContext.RIP;
fpRegIndex = AMD64ThreadContext.RBP;
+ } else if (cpu.equals("ppc64")) {
+ threadFactory = new ProcPPC64ThreadFactory(this);
+ pcRegIndex = PPC64ThreadContext.PC;
+ fpRegIndex = PPC64ThreadContext.SP;
} else {
try {
Class tfc = Class.forName("sun.jvm.hotspot.debugger.proc." +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/proc/ppc64/ProcPPC64Thread.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.proc.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.proc.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class ProcPPC64Thread implements ThreadProxy {
+ private ProcDebugger debugger;
+ private int id;
+
+ public ProcPPC64Thread(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 ProcPPC64Thread(ProcDebugger debugger, long id) {
+ this.debugger = debugger;
+ this.id = (int) id;
+ }
+
+ public ThreadContext getContext() throws IllegalThreadStateException {
+ ProcPPC64ThreadContext context = new ProcPPC64ThreadContext(debugger);
+ long[] regs = debugger.getThreadIntegerRegisterSet(id);
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(regs.length <= PPC64ThreadContext.NPRGREG, "size of register set is greater than " + PPC64ThreadContext.NPRGREG);
+ }
+ 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 ProcPPC64Thread)) {
+ return false;
+ }
+
+ return (((ProcPPC64Thread) 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/ppc64/ProcPPC64ThreadContext.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.proc.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.proc.*;
+
+public class ProcPPC64ThreadContext extends PPC64ThreadContext {
+ private ProcDebugger debugger;
+
+ public ProcPPC64ThreadContext(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/ppc64/ProcPPC64ThreadFactory.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.proc.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.proc.*;
+
+public class ProcPPC64ThreadFactory implements ProcThreadFactory {
+ private ProcDebugger debugger;
+
+ public ProcPPC64ThreadFactory(ProcDebugger debugger) {
+ this.debugger = debugger;
+ }
+
+ public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) {
+ return new ProcPPC64Thread(debugger, threadIdentifierAddr);
+ }
+
+ public ThreadProxy createThreadWrapper(long id) {
+ return new ProcPPC64Thread(debugger, id);
+ }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/RemoteDebuggerClient.java Fri Jan 16 12:33:47 2015 -0800
@@ -33,6 +33,7 @@
import sun.jvm.hotspot.debugger.remote.sparc.*;
import sun.jvm.hotspot.debugger.remote.x86.*;
import sun.jvm.hotspot.debugger.remote.amd64.*;
+import sun.jvm.hotspot.debugger.remote.ppc64.*;
/** An implementation of Debugger which wraps a
RemoteDebugger, providing remote debugging via RMI.
@@ -70,6 +71,11 @@
cachePageSize = 4096;
cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
unalignedAccessesOkay = true;
+ } else if (cpu.equals("ppc64")) {
+ threadFactory = new RemotePPC64ThreadFactory(this);
+ cachePageSize = 4096;
+ cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
+ unalignedAccessesOkay = true;
} else {
try {
Class tf = Class.forName("sun.jvm.hotspot.debugger.remote." +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/debugger/remote/ppc64/RemotePPC64Thread.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.remote.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.remote.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class RemotePPC64Thread extends RemoteThread {
+ public RemotePPC64Thread(RemoteDebuggerClient debugger, Address addr) {
+ super(debugger, addr);
+ }
+
+ public RemotePPC64Thread(RemoteDebuggerClient debugger, long id) {
+ super(debugger, id);
+ }
+
+ public ThreadContext getContext() throws IllegalThreadStateException {
+ RemotePPC64ThreadContext context = new RemotePPC64ThreadContext(debugger);
+ long[] regs = (addr != null)? debugger.getThreadIntegerRegisterSet(addr) :
+ debugger.getThreadIntegerRegisterSet(id);
+ if (Assert.ASSERTS_ENABLED) {
+ Assert.that(regs.length == PPC64ThreadContext.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/ppc64/RemotePPC64ThreadContext.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.remote.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.remote.*;
+
+public class RemotePPC64ThreadContext extends PPC64ThreadContext {
+ private RemoteDebuggerClient debugger;
+
+ public RemotePPC64ThreadContext(RemoteDebuggerClient debugger) {
+ super();
+ this.debugger = debugger;
+ }
+
+ /** This can't be implemented in this class since we would have to
+ tie the implementation to, for example, the debugging system */
+ public void setRegisterAsAddress(int index, Address value) {
+ setRegister(index, debugger.getAddressValue(value));
+ }
+
+ /** This can't be implemented in this class since we would have to
+ tie the implementation to, for example, the debugging system */
+ 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/ppc64/RemotePPC64ThreadFactory.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.remote.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.remote.*;
+
+public class RemotePPC64ThreadFactory implements RemoteThreadFactory {
+ private RemoteDebuggerClient debugger;
+
+ public RemotePPC64ThreadFactory(RemoteDebuggerClient debugger) {
+ this.debugger = debugger;
+ }
+
+ public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) {
+ return new RemotePPC64Thread(debugger, threadIdentifierAddr);
+ }
+
+ public ThreadProxy createThreadWrapper(long id) {
+ return new RemotePPC64Thread(debugger, id);
+ }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java Fri Jan 16 12:33:47 2015 -0800
@@ -25,6 +25,7 @@
package sun.jvm.hotspot.runtime;
import java.util.*;
+
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.types.*;
import sun.jvm.hotspot.runtime.solaris_sparc.SolarisSPARCJavaThreadPDAccess;
@@ -34,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_ppc64.LinuxPPC64JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.linux_sparc.LinuxSPARCJavaThreadPDAccess;
import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess;
import sun.jvm.hotspot.runtime.bsd_amd64.BsdAMD64JavaThreadPDAccess;
@@ -87,6 +89,8 @@
access = new LinuxAMD64JavaThreadPDAccess();
} else if (cpu.equals("sparc")) {
access = new LinuxSPARCJavaThreadPDAccess();
+ } else if (cpu.equals("ppc64")) {
+ access = new LinuxPPC64JavaThreadPDAccess();
} else {
try {
access = (JavaThreadPDAccess)
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/VFrame.java Fri Jan 16 12:33:47 2015 -0800
@@ -78,7 +78,7 @@
}
if (f.isRuntimeFrame()) {
- // This is a conversion frame. Skip this frame and try again.
+ // This is a conversion frame or a Stub routine. Skip this frame and try again.
RegisterMap tempMap = regMap.copy();
Frame s = f.sender(tempMap);
return newVFrame(s, tempMap, thread, unsafe, false);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/linux_ppc64/LinuxPPC64JavaThreadPDAccess.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.linux_ppc64;
+
+import java.io.*;
+import java.util.*;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.ppc64.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+
+public class LinuxPPC64JavaThreadPDAccess implements JavaThreadPDAccess {
+ 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 osThreadType = db.lookupType("OSThread");
+ osThreadThreadIDField = osThreadType.getCIntegerField("_thread_id");
+ }
+
+ public Address getLastJavaFP(Address addr) {
+ return null;
+ }
+
+ 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 PPC64Frame(thread.getLastJavaSP(), fp);
+ }
+
+ public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) {
+ return new PPC64RegisterMap(thread, updateMap);
+ }
+
+ public Frame getCurrentFrameGuess(JavaThread thread, Address addr) {
+ ThreadProxy t = getThreadProxy(addr);
+ PPC64ThreadContext context = (PPC64ThreadContext) t.getContext();
+ PPC64CurrentFrameGuess guesser = new PPC64CurrentFrameGuess(context, thread);
+ if (!guesser.run(GUESS_SCAN_RANGE)) {
+ return null;
+ }
+ if (guesser.getPC() == null) {
+ return new PPC64Frame(guesser.getSP(), guesser.getFP());
+ } else {
+ return new PPC64Frame(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);
+ PPC64ThreadContext context = (PPC64ThreadContext) t.getContext();
+ return context.getRegisterAsAddress(PPC64ThreadContext.SP);
+ }
+
+ public Address getLastFP(Address addr) {
+ return getLastSP(addr).getAddressAt(0);
+ }
+
+ 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);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64CurrentFrameGuess.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.code.*;
+import sun.jvm.hotspot.interpreter.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.ppc64.*;
+
+/** <P> Should be able to be used on all ppc64 platforms we support
+ (Linux/ppc64) to implement JavaThread's "currentFrameGuess()"
+ functionality. Input is a PPC64ThreadContext; output is SP, FP,
+ and PC for an PPC64Frame. Instantiation of the PPC64Frame is left
+ to the caller, since we may need to subclass PPC64Frame to support
+ signal handler frames on Unix platforms. </P>
+ */
+
+public class PPC64CurrentFrameGuess {
+ private PPC64ThreadContext context;
+ private JavaThread thread;
+ private Address spFound;
+ private Address fpFound;
+ private Address pcFound;
+
+ private static final boolean DEBUG;
+ static {
+ DEBUG = System.getProperty("sun.jvm.hotspot.runtime.ppc64.PPC64Frame.DEBUG") != null;
+ }
+
+ public PPC64CurrentFrameGuess(PPC64ThreadContext 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(PPC64ThreadContext.SP);
+ Address pc = context.getRegisterAsAddress(PPC64ThreadContext.PC);
+ if (sp == null) {
+ // Bail out if no last java frame either
+ if (thread.getLastJavaSP() != null) {
+ Address javaSP = thread.getLastJavaSP();
+ Address javaFP = javaSP.getAddressAt(0);
+ setValues(javaSP, javaFP, null);
+ return true;
+ }
+ return false;
+ }
+ /* There is no frame pointer per se for the ppc64 architecture. To mirror
+ * the behavior of the VM frame manager, we set fp to be the caller's (i.e., "sender's")
+ * stack pointer, which is the back chain value contained in our sp.
+ */
+ Address fp = sp.getAddressAt(0);
+ setValues(null, null, null); // Assume we're not going to find anything
+
+ VM vm = VM.getVM();
+ if (vm.isJavaPCDbg(pc)) {
+ if (vm.isClientCompiler()) {
+ // Topmost frame is a Java frame.
+ if (DEBUG) {
+ System.out.println("CurrentFrameGuess: choosing compiler frame: sp = " +
+ sp + ", fp = " + fp + ", pc = " + pc);
+ }
+ 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;
+ }
+
+ // 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).
+ for (long offset = 0;
+ offset < regionInBytesToSearch;
+ offset += vm.getAddressSize()) {
+ try {
+ Address curSP = sp.addOffsetTo(offset);
+ fp = curSP.getAddressAt(0);
+ Frame frame = new PPC64Frame(curSP, fp, 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, fp, 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;
+
+ }
+ } 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 java SP.
+ // Note that if this is 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 (thread.getLastJavaSP() == null) {
+ if (DEBUG) {
+ System.out.println("CurrentFrameGuess: last java sp is null");
+ }
+ return false; // No known Java frames on stack
+ }
+
+ Address javaSP = thread.getLastJavaSP();
+ Address javaFP = javaSP.getAddressAt(0);
+ Address javaPC = thread.getLastJavaPC();
+ if (DEBUG) {
+ System.out.println("CurrentFrameGuess: choosing last Java frame: sp = " +
+ javaSP + ", fp = " + javaFP + ", pc = " + javaPC);
+ }
+ setValues(javaSP, javaFP, javaPC);
+ 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 PPC64Frame 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/ppc64/PPC64Frame.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,513 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.ppc64;
+
+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 ppc64 family of CPUs. */
+
+public class PPC64Frame extends Frame {
+ private static final boolean DEBUG;
+ static {
+ DEBUG = System.getProperty("sun.jvm.hotspot.runtime.ppc64.PPC64Frame.DEBUG") != null;
+ }
+
+ // All frames
+ private static final int SENDER_SP_OFFSET = 0;
+
+ // Interpreter frames
+ private static final int INTERPRETER_FRAME_MIRROR_OFFSET = -3; // for native calls only
+ private static final int INTERPRETER_FRAME_SENDER_SP_OFFSET = -4;
+ private static final int INTERPRETER_FRAME_LAST_SP_OFFSET = INTERPRETER_FRAME_SENDER_SP_OFFSET - 1;
+ private static final int INTERPRETER_FRAME_MDX_OFFSET = INTERPRETER_FRAME_LAST_SP_OFFSET -1;
+ private static final int INTERPRETER_FRAME_ESP_OFFSET = INTERPRETER_FRAME_MDX_OFFSET - 1;
+ private static final int INTERPRETER_FRAME_BCX_OFFSET = INTERPRETER_FRAME_ESP_OFFSET - 1;
+ private static final int INTERPRETER_FRAME_CACHE_OFFSET =INTERPRETER_FRAME_BCX_OFFSET - 1;
+ private static final int INTERPRETER_FRAME_MONITORS_OFFSET = INTERPRETER_FRAME_CACHE_OFFSET - 1;
+ private static final int INTERPRETER_FRAME_LOCALS_OFFSET = INTERPRETER_FRAME_MONITORS_OFFSET - 1;
+ private static final int INTERPRETER_FRAME_METHOD_OFFSET = INTERPRETER_FRAME_LOCALS_OFFSET - 1;
+ private static final int INTERPRETER_FRAME_INITIAL_SP_OFFSET = INTERPRETER_FRAME_BCX_OFFSET - 1; // FIXME: probably wrong, but unused anyway
+ private static final int INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
+ private static final int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET;
+
+ // Entry frames
+ private static int ENTRY_FRAME_CALL_WRAPPER_OFFSET;
+
+ // Native frames
+ private static int NATIVE_FRAME_INITIAL_PARAM_OFFSET;
+
+
+ static {
+ VM.registerVMInitializedObserver(new Observer() {
+ public void update(Observable o, Object data) {
+ initialize(VM.getVM().getTypeDataBase());
+ }
+ });
+ }
+
+ private static synchronized void initialize(TypeDataBase db) {
+ int abi_minframe_size = db.lookupIntConstant("frame::abi_minframe_size").intValue();
+ int entry_frame_locals_size = db.lookupIntConstant("frame::entry_frame_locals_size").intValue();
+ int wordLength = (int) VM.getVM().getAddressSize();
+ NATIVE_FRAME_INITIAL_PARAM_OFFSET = -abi_minframe_size/wordLength;
+ ENTRY_FRAME_CALL_WRAPPER_OFFSET = -entry_frame_locals_size/wordLength;
+ }
+
+
+ // an additional field beyond sp and pc:
+ Address raw_fp; // frame pointer
+ private Address raw_unextendedSP;
+
+ private PPC64Frame() {
+ }
+
+ 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 PPC64Frame(Address raw_sp, Address raw_fp, Address pc) {
+ this.raw_sp = raw_sp;
+ this.raw_unextendedSP = raw_sp;
+ if (raw_fp == null) {
+ this.raw_fp = raw_sp.getAddressAt(0);
+ } else {
+ this.raw_fp = raw_fp;
+ }
+ if (pc == null) {
+ this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize());
+ } else {
+ this.pc = pc;
+ }
+ adjustUnextendedSP();
+
+ // Frame must be fully constructed before this call
+ adjustForDeopt();
+
+ if (DEBUG) {
+ System.out.println("PPC64Frame(sp, fp, pc): " + this);
+ dumpStack();
+ }
+ }
+
+ public PPC64Frame(Address raw_sp, Address raw_fp) {
+ this.raw_sp = raw_sp;
+ this.raw_unextendedSP = raw_sp;
+ if (raw_fp == null) {
+ this.raw_fp = raw_sp.getAddressAt(0);
+ } else {
+ this.raw_fp = raw_fp;
+ }
+ this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize());
+ adjustUnextendedSP();
+
+ // Frame must be fully constructed before this call
+ adjustForDeopt();
+
+ if (DEBUG) {
+ System.out.println("PPC64Frame(sp, fp): " + this);
+ dumpStack();
+ }
+ }
+
+ public PPC64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) {
+ this.raw_sp = raw_sp;
+ this.raw_unextendedSP = raw_unextendedSp;
+ if (raw_fp == null) {
+ this.raw_fp = raw_sp.getAddressAt(0);
+ } else {
+ this.raw_fp = raw_fp;
+ }
+ if (pc == null) {
+ this.pc = raw_sp.getAddressAt(2 * VM.getVM().getAddressSize());
+ } else {
+ this.pc = pc;
+ }
+ adjustUnextendedSP();
+
+ // Frame must be fully constructed before this call
+ adjustForDeopt();
+
+ if (DEBUG) {
+ System.out.println("PPC64Frame(sp, unextendedSP, fp, pc): " + this);
+ dumpStack();
+ }
+
+ }
+
+ public Object clone() {
+ PPC64Frame frame = new PPC64Frame();
+ 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 PPC64Frame)) {
+ return false;
+ }
+
+ PPC64Frame other = (PPC64Frame) 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 (should be done for Solaris/PPC64)
+ 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;
+ }
+
+ // 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) {
+ PPC64RegisterMap map = (PPC64RegisterMap) 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 PPC64Frame(getSenderSP(), getLink(), getSenderPC());
+ }
+
+ private Frame senderForEntryFrame(PPC64RegisterMap 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
+ PPC64JavaCallWrapper jcw = (PPC64JavaCallWrapper) 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");
+ }
+ PPC64Frame fr;
+ if (jcw.getLastJavaPC() != null) {
+ fr = new PPC64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC());
+ } else {
+ fr = new PPC64Frame(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() {
+ raw_unextendedSP = getFP();
+ }
+ private Frame senderForInterpreterFrame(PPC64RegisterMap map) {
+ if (DEBUG) {
+ System.out.println("senderForInterpreterFrame");
+ }
+ Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0);
+ Address sp = getSenderSP();
+
+ return new PPC64Frame(sp, unextendedSP, getLink(), getSenderPC());
+ }
+
+
+ private Frame senderForCompiledFrame(PPC64RegisterMap map, CodeBlob cb) {
+ if (DEBUG) {
+ System.out.println("senderForCompiledFrame");
+ }
+
+ //
+ // NOTE: some of this code is (unfortunately) duplicated in PPC64CurrentFrameGuess
+ //
+
+ 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 = getSenderSP();
+
+ Address senderPC = getSenderPC();
+
+ 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) {
+ OopMapSet.updateRegisterMap(this, cb, map, true);
+ }
+ }
+
+ return new PPC64Frame(senderSP, getLink(), senderPC);
+ }
+
+ protected boolean hasSenderPD() {
+ // FIXME
+ return true;
+ }
+
+ public long frameSize() {
+ return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize());
+ }
+
+ public Address getLink() {
+ return getSenderSP().getAddressAt(0);
+ }
+
+ public Address getUnextendedSP() { return raw_unextendedSP; }
+
+ // Return address:
+ public Address getSenderPC() { return getSenderSP().getAddressAt(2 * VM.getVM().getAddressSize()); }
+
+ // return address of param, zero origin index.
+ // MPJ note: Appears to be unused.
+ public Address getNativeParamAddr(int idx) {
+ return null;
+ // return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx);
+ }
+
+ public Address getSenderSP() { return getFP(); }
+ 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 PPC64JavaCallWrapper(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() {
+ if (getFP() != null) {
+ for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize());
+ AddressOps.lte(addr, getFP().addOffsetTo(5 * VM.getVM().getAddressSize()));
+ addr = addr.addOffsetTo(VM.getVM().getAddressSize())) {
+ System.out.println(addr + ": " + addr.getAddressAt(0));
+ }
+ } else {
+ for (Address addr = getSP().addOffsetTo(-5 * VM.getVM().getAddressSize());
+ 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/ppc64/PPC64JavaCallWrapper.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.ppc64;
+
+import java.util.*;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.runtime.*;
+
+public class PPC64JavaCallWrapper extends JavaCallWrapper {
+
+ public PPC64JavaCallWrapper(Address addr) {
+ super(addr);
+ }
+
+ public Address getLastJavaFP() {
+ return null;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64RegisterMap.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 20014, Oracle and/or its affiliates. All rights reserved.
+ * 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.ppc64;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.runtime.*;
+
+public class PPC64RegisterMap extends RegisterMap {
+
+ /** This is the only public constructor */
+ public PPC64RegisterMap(JavaThread thread, boolean updateMap) {
+ super(thread, updateMap);
+ }
+
+ protected PPC64RegisterMap(RegisterMap map) {
+ super(map);
+ }
+
+ public Object clone() {
+ PPC64RegisterMap retval = new PPC64RegisterMap(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; }
+}
--- a/hotspot/make/aix/makefiles/ppc64.make Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/make/aix/makefiles/ppc64.make Fri Jan 16 12:33:47 2015 -0800
@@ -46,7 +46,9 @@
# - 1540-1090 (I) The destructor of "..." might not be called.
# - 1500-010: (W) WARNING in ...: Infinite loop. Program may not stop.
# There are several infinite loops in the vm, suppress.
-CFLAGS += -qsuppress=1540-1090 -qsuppress=1500-010
+# - 1540-1639 (I) The behavior of long type bit fields has changed ...
+# ... long type bit fields now default to long, not int.
+CFLAGS += -qsuppress=1540-1090 -qsuppress=1500-010 -qsuppress=1540-1639
# Suppress
# - 540-1088 (W) The exception specification is being ignored.
--- a/hotspot/make/aix/makefiles/xlc.make Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/make/aix/makefiles/xlc.make Fri Jan 16 12:33:47 2015 -0800
@@ -124,7 +124,7 @@
# MAPFLAG = -Xlinker --version-script=FILENAME
# Build shared library
-SHARED_FLAG = -q64 -b64 -bexpall -G -bnoentry -qmkshrobj -brtl -bnolibpath
+SHARED_FLAG = -q64 -b64 -bexpall -G -bnoentry -qmkshrobj -brtl -bnolibpath -bernotok
#------------------------------------------------------------------------
# Debug flags
--- a/hotspot/make/linux/makefiles/sa.make Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/make/linux/makefiles/sa.make Fri Jan 16 12:33:47 2015 -0800
@@ -109,6 +109,7 @@
$(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.x86.X86ThreadContext
$(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.amd64.AMD64ThreadContext
$(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.sparc.SPARCThreadContext
+ $(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.debugger.ppc64.PPC64ThreadContext
$(QUIETLY) $(REMOTE) $(RUN.JAVAH) -classpath $(SA_CLASSDIR) -d $(GENERATED) -jni sun.jvm.hotspot.asm.Disassembler
clean:
--- a/hotspot/make/sa.files Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/make/sa.files Fri Jan 16 12:33:47 2015 -0800
@@ -51,16 +51,20 @@
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/dummy/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/amd64/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/linux/ppc64/*.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 \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/posix/elf/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/ppc64/*.java \
$(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/sparc/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/proc/x86/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/debugger/remote/amd64/*.java \
+$(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/sparc/*.java \
@@ -90,12 +94,14 @@
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/linux_amd64/*.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 \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/posix/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_amd64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_sparc/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/solaris_x86/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/sparc/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/x86/*.java \
+$(AGENT_SRC_DIR)/sun/jvm/hotspot/runtime/ppc64/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/jcore/*.java \
$(AGENT_SRC_DIR)/sun/jvm/hotspot/tools/soql/*.java \
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -59,7 +59,7 @@
_has_nonstatic_fields = ik->has_nonstatic_fields();
_has_default_methods = ik->has_default_methods();
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
-
+ _has_injected_fields = -1;
_implementor = NULL; // we will fill these lazily
Thread *thread = Thread::current();
@@ -100,6 +100,7 @@
_nonstatic_field_size = -1;
_has_nonstatic_fields = false;
_nonstatic_fields = NULL;
+ _has_injected_fields = -1;
_loader = loader;
_protection_domain = protection_domain;
_is_shared = false;
@@ -500,6 +501,34 @@
return fields;
}
+void ciInstanceKlass::compute_injected_fields_helper() {
+ ASSERT_IN_VM;
+ InstanceKlass* k = get_instanceKlass();
+
+ for (InternalFieldStream fs(k); !fs.done(); fs.next()) {
+ if (fs.access_flags().is_static()) continue;
+ _has_injected_fields++;
+ break;
+ }
+}
+
+bool ciInstanceKlass::compute_injected_fields() {
+ assert(_has_injected_fields == -1, "shouldn't be initialized yet");
+ assert(is_loaded(), "must be loaded");
+
+ if (super() != NULL && super()->has_injected_fields()) {
+ _has_injected_fields = 1;
+ return true;
+ }
+
+ _has_injected_fields = 0;
+ GUARDED_VM_ENTRY({
+ compute_injected_fields_helper();
+ });
+
+ return _has_injected_fields > 0 ? true : false;
+}
+
// ------------------------------------------------------------------
// ciInstanceKlass::find_method
//
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -64,6 +64,7 @@
ciConstantPoolCache* _field_cache; // cached map index->field
GrowableArray<ciField*>* _nonstatic_fields;
+ int _has_injected_fields; // any non static injected fields? lazily initialized.
// The possible values of the _implementor fall into following three cases:
// NULL: no implementor.
@@ -71,6 +72,9 @@
// Itsef: more than one implementors.
ciInstanceKlass* _implementor;
+ bool compute_injected_fields();
+ void compute_injected_fields_helper();
+
protected:
ciInstanceKlass(KlassHandle h_k);
ciInstanceKlass(ciSymbol* name, jobject loader, jobject protection_domain);
@@ -186,6 +190,14 @@
else
return _nonstatic_fields->length();
}
+
+ bool has_injected_fields() {
+ if (_has_injected_fields == -1) {
+ return compute_injected_fields();
+ }
+ return _has_injected_fields > 0 ? true : false;
+ }
+
// nth nonstatic field (presented by ascending address)
ciField* nonstatic_field_at(int i) {
assert(_nonstatic_fields != NULL, "");
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -786,17 +786,12 @@
MetadataOnStackMark md_on_stack(has_redefined_a_class);
if (has_redefined_a_class) {
- // purge_previous_versions also cleans weak method links. Because
- // one method's MDO can reference another method from another
- // class loader, we need to first clean weak method links for all
- // class loaders here. Below, we can then free redefined methods
- // for all class loaders.
for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
data->classes_do(InstanceKlass::purge_previous_versions);
}
}
- // Need to purge the previous version before deallocating.
+ // Should purge the previous version before deallocating.
free_deallocate_lists();
}
@@ -834,8 +829,6 @@
void ClassLoaderDataGraph::free_deallocate_lists() {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
- // We need to keep this data until InstanceKlass::purge_previous_version has been
- // called on all alive classes. See the comment in ClassLoaderDataGraph::clean_metaspaces.
cld->free_deallocate_list();
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/javaClasses.hpp"
+#include "memory/metaspaceShared.hpp"
+#include "utilities/numberSeq.hpp"
+#include <sys/stat.h>
+
+/////////////////////////////////////////////////////
+//
+// The compact hash table writer implementations
+//
+CompactHashtableWriter::CompactHashtableWriter(const char* table_name,
+ int num_entries,
+ CompactHashtableStats* stats) {
+ assert(DumpSharedSpaces, "dump-time only");
+ _table_name = table_name;
+ _num_entries = num_entries;
+ _num_buckets = number_of_buckets(_num_entries);
+ _buckets = NEW_C_HEAP_ARRAY(Entry*, _num_buckets, mtSymbol);
+ memset(_buckets, 0, sizeof(Entry*) * _num_buckets);
+
+ /* bucket sizes table */
+ _bucket_sizes = NEW_C_HEAP_ARRAY(juint, _num_buckets, mtSymbol);
+ memset(_bucket_sizes, 0, sizeof(juint) * _num_buckets);
+
+ stats->hashentry_count = _num_entries;
+ // Compact buckets' entries will have only the 4-byte offset, but
+ // we don't know how many there will be at this point. So use a
+ // conservative estimate here. The size is adjusted later when we
+ // write out the buckets.
+ stats->hashentry_bytes = _num_entries * 8;
+ stats->bucket_count = _num_buckets;
+ stats->bucket_bytes = (_num_buckets + 1) * (sizeof(juint));
+ _stats = stats;
+
+ // See compactHashtable.hpp for table layout
+ _required_bytes = sizeof(juint) * 2; // _base_address, written as 2 juints
+ _required_bytes+= sizeof(juint) + // num_entries
+ sizeof(juint) + // num_buckets
+ stats->hashentry_bytes +
+ stats->bucket_bytes;
+}
+
+CompactHashtableWriter::~CompactHashtableWriter() {
+ for (int index = 0; index < _num_buckets; index++) {
+ Entry* next = NULL;
+ for (Entry* tent = _buckets[index]; tent; tent = next) {
+ next = tent->next();
+ delete tent;
+ }
+ }
+
+ FREE_C_HEAP_ARRAY(juint, _bucket_sizes);
+ FREE_C_HEAP_ARRAY(Entry*, _buckets);
+}
+
+// Calculate the number of buckets in the temporary hash table
+int CompactHashtableWriter::number_of_buckets(int num_entries) {
+ const int buksize = (int)SharedSymbolTableBucketSize;
+ int num_buckets = (num_entries + buksize - 1) / buksize;
+ num_buckets = (num_buckets + 1) & (~0x01);
+
+ return num_buckets;
+}
+
+// Add a symbol entry to the temporary hash table
+void CompactHashtableWriter::add(unsigned int hash, Entry* entry) {
+ int index = hash % _num_buckets;
+ entry->set_next(_buckets[index]);
+ _buckets[index] = entry;
+ _bucket_sizes[index] ++;
+}
+
+// Write the compact table's bucket infos
+juint* CompactHashtableWriter::dump_table(juint* p, juint** first_bucket,
+ NumberSeq* summary) {
+ int index;
+ juint* compact_table = p;
+ // Find the start of the buckets, skip the compact_bucket_infos table
+ // and the table end offset.
+ juint offset = _num_buckets + 1;
+ *first_bucket = compact_table + offset;
+
+ for (index = 0; index < _num_buckets; index++) {
+ int bucket_size = _bucket_sizes[index];
+ if (bucket_size == 1) {
+ // bucket with one entry is compacted and only has the symbol offset
+ compact_table[index] = BUCKET_INFO(offset, COMPACT_BUCKET_TYPE);
+ offset += bucket_size; // each entry contains symbol offset only
+ } else {
+ // regular bucket, each entry is a symbol (hash, offset) pair
+ compact_table[index] = BUCKET_INFO(offset, REGULAR_BUCKET_TYPE);
+ offset += bucket_size * 2; // each hash entry is 2 juints
+ }
+ if (offset & ~BUCKET_OFFSET_MASK) {
+ vm_exit_during_initialization("CompactHashtableWriter::dump_table: Overflow! "
+ "Too many symbols.");
+ }
+ summary->add(bucket_size);
+ }
+ // Mark the end of the table
+ compact_table[_num_buckets] = BUCKET_INFO(offset, TABLEEND_BUCKET_TYPE);
+
+ return compact_table;
+}
+
+// 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");
+ int num_compact_buckets = 0;
+
+ assert(p != NULL, "sanity");
+ for (int index = 0; index < _num_buckets; index++) {
+ juint count = 0;
+ int bucket_size = _bucket_sizes[index];
+ int bucket_type = BUCKET_TYPE(compact_table[index]);
+
+ if (bucket_size == 1) {
+ assert(bucket_type == COMPACT_BUCKET_TYPE, "Bad bucket type");
+ num_compact_buckets ++;
+ }
+ for (Entry* tent = _buckets[index]; tent;
+ tent = tent->next()) {
+ if (bucket_type == REGULAR_BUCKET_TYPE) {
+ *p++ = juint(tent->hash()); // write symbol hash
+ }
+ uintx deltax = uintx(tent->value()) - base_address;
+ assert(deltax < max_delta, "range check");
+ juint delta = juint(deltax);
+ *p++ = delta; // write symbol offset
+ count ++;
+ }
+ assert(count == _bucket_sizes[index], "sanity");
+ }
+
+ // Adjust the hashentry_bytes in CompactHashtableStats. Each compact
+ // bucket saves 4-byte.
+ _stats->hashentry_bytes -= num_compact_buckets * 4;
+
+ return p;
+}
+
+// Write the compact table
+void CompactHashtableWriter::dump(char** top, char* end) {
+ NumberSeq summary;
+ char* old_top = *top;
+ juint* p = (juint*)(*top);
+
+ uintx base_address = uintx(MetaspaceShared::shared_rs()->base());
+
+ *p++ = high(base_address);
+ *p++ = low (base_address); // base address
+ *p++ = _num_entries; // number of entries in the table
+ *p++ = _num_buckets; // number of buckets in the table
+
+ juint* first_bucket = NULL;
+ juint* compact_table = dump_table(p, &first_bucket, &summary);
+ juint* bucket_end = dump_buckets(compact_table, first_bucket, &summary);
+
+ assert(bucket_end <= (juint*)end, "cannot write past end");
+ *top = (char*)bucket_end;
+
+ if (PrintSharedSpaces) {
+ double avg_cost = 0.0;
+ 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("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);
+ tty->print_cr("Average bucket size : %9.3f", summary.avg());
+ tty->print_cr("Variance of bucket size : %9.3f", summary.variance());
+ tty->print_cr("Std. dev. of bucket size: %9.3f", summary.sd());
+ tty->print_cr("Maximum bucket size : %9d", (int)summary.maximum());
+ }
+}
+
+/////////////////////////////////////////////////////////////
+//
+// The CompactHashtable implementation
+//
+template <class T, class N> const char* CompactHashtable<T, N>::init(const char* buffer) {
+ assert(!DumpSharedSpaces, "run-time only");
+ juint*p = (juint*)buffer;
+ juint upper = *p++;
+ juint lower = *p++;
+ _base_address = uintx(jlong_from(upper, lower));
+ _entry_count = *p++;
+ _bucket_count = *p++;
+ _buckets = p;
+ _table_end_offset = BUCKET_OFFSET(p[_bucket_count]); // located at the end of the bucket_info table
+
+ juint *end = _buckets + _table_end_offset;
+ return (const char*)end;
+}
+
+// Explicitly instantiate these types
+template class CompactHashtable<Symbol*, char>;
+
+#ifndef O_BINARY // if defined (Win32) use binary files.
+#define O_BINARY 0 // otherwise do nothing.
+#endif
+
+////////////////////////////////////////////////////////
+//
+// HashtableTextDump
+//
+HashtableTextDump::HashtableTextDump(const char* filename) : _fd(-1) {
+ struct stat st;
+ if (os::stat(filename, &st) != 0) {
+ quit("Unable to get hashtable dump file size", filename);
+ }
+ _size = st.st_size;
+ _fd = open(filename, O_RDONLY | O_BINARY, 0);
+ if (_fd < 0) {
+ quit("Unable to open hashtable dump file", filename);
+ }
+ _base = os::map_memory(_fd, filename, 0, NULL, _size, true, false);
+ if (_base == NULL) {
+ quit("Unable to map hashtable dump file", filename);
+ }
+ _p = _base;
+ _end = _base + st.st_size;
+ _filename = filename;
+}
+
+HashtableTextDump::~HashtableTextDump() {
+ os::unmap_memory((char*)_base, _size);
+ if (_fd >= 0) {
+ close(_fd);
+ }
+}
+
+void HashtableTextDump::quit(const char* err, const char* msg) {
+ vm_exit_during_initialization(err, msg);
+}
+
+void HashtableTextDump::corrupted(const char *p) {
+ char info[60];
+ sprintf(info, "corrupted at pos %d", (int)(p - _base));
+ quit(info, _filename);
+}
+
+bool HashtableTextDump::skip_newline() {
+ if (_p[0] == '\r' && _p[1] == '\n') {
+ _p += 2;
+ } else if (_p[0] == '\n') {
+ _p += 1;
+ } else {
+ corrupted(_p);
+ }
+ return true;
+}
+
+int HashtableTextDump::skip(char must_be_char) {
+ corrupted_if(remain() < 1);
+ corrupted_if(*_p++ != must_be_char);
+ return 0;
+}
+
+void HashtableTextDump::skip_past(char c) {
+ for (;;) {
+ corrupted_if(remain() < 1);
+ if (*_p++ == c) {
+ return;
+ }
+ }
+}
+
+void HashtableTextDump::check_version(const char* ver) {
+ int len = (int)strlen(ver);
+ corrupted_if(remain() < len);
+ if (strncmp(_p, ver, len) != 0) {
+ quit("wrong version of hashtable dump file", _filename);
+ }
+ _p += len;
+ skip_newline();
+}
+
+
+int HashtableTextDump::scan_prefix() {
+ // Expect /[0-9]+: /
+ int utf8_length = get_num(':');
+ if (*_p != ' ') {
+ corrupted(_p);
+ }
+ _p++;
+ return utf8_length;
+}
+
+int HashtableTextDump::scan_prefix2() {
+ // Expect /[0-9]+ (-|)[0-9]+: /
+ int utf8_length = get_num(' ');
+ if (*_p == '-') {
+ _p++;
+ }
+ (void)get_num(':');
+ if (*_p != ' ') {
+ corrupted(_p);
+ }
+ _p++;
+ return utf8_length;
+}
+
+jchar HashtableTextDump::unescape(const char* from, const char* end, int count) {
+ jchar value = 0;
+
+ corrupted_if(from + count > end);
+
+ for (int i=0; i<count; i++) {
+ char c = *from++;
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ value = (value << 4) + c - '0';
+ break;
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+ value = (value << 4) + 10 + c - 'a';
+ break;
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ value = (value << 4) + 10 + c - 'A';
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ }
+ return value;
+}
+
+void HashtableTextDump::get_utf8(char* utf8_buffer, int utf8_length) {
+ // cache in local vars
+ const char* from = _p;
+ const char* end = _end;
+ char* to = utf8_buffer;
+ int n = utf8_length;
+
+ for (; n > 0 && from < end; n--) {
+ if (*from != '\\') {
+ *to++ = *from++;
+ } else {
+ corrupted_if(from + 2 > end);
+ char c = from[1];
+ from += 2;
+ switch (c) {
+ case 'x':
+ {
+ jchar value = unescape(from, end, 2);
+ from += 2;
+ assert(value <= 0xff, "sanity");
+ *to++ = (char)(value & 0xff);
+ }
+ break;
+ case 't': *to++ = '\t'; break;
+ case 'n': *to++ = '\n'; break;
+ case 'r': *to++ = '\r'; break;
+ case '\\': *to++ = '\\'; break;
+ default:
+ ShouldNotReachHere();
+ }
+ }
+ }
+ corrupted_if(n > 0); // expected more chars but file has ended
+ _p = from;
+ skip_newline();
+}
+
+// NOTE: the content is NOT the same as
+// UTF8::as_quoted_ascii(const char* utf8_str, int utf8_length, char* buf, int buflen).
+// We want to escape \r\n\t so that output [1] is more readable; [2] can be more easily
+// parsed by scripts; [3] quickly processed by HashtableTextDump::get_utf8()
+void HashtableTextDump::put_utf8(outputStream* st, const char* utf8_string, int utf8_length) {
+ const char *c = utf8_string;
+ const char *end = c + utf8_length;
+ for (; c < end; c++) {
+ switch (*c) {
+ case '\t': st->print("\\t"); break;
+ case '\r': st->print("\\r"); break;
+ case '\n': st->print("\\n"); break;
+ case '\\': st->print("\\\\"); break;
+ default:
+ if (isprint(*c)) {
+ st->print("%c", *c);
+ } else {
+ st->print("\\x%02x", ((unsigned int)*c) & 0xff);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP
+#define SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP
+
+#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
+#include "memory/allocation.inline.hpp"
+#include "oops/symbol.hpp"
+#include "services/diagnosticCommand.hpp"
+#include "utilities/hashtable.hpp"
+
+class NumberSeq;
+
+// Stats for symbol tables in the CDS archive
+class CompactHashtableStats VALUE_OBJ_CLASS_SPEC {
+public:
+ int hashentry_count;
+ int hashentry_bytes;
+ int bucket_count;
+ int bucket_bytes;
+};
+
+/////////////////////////////////////////////////////////////////////////
+//
+// The compact hash table writer. Used at dump time for writing out
+// 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
+// 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.
+// 4 is chosen because it produces smaller sized bucket on average for
+// 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.
+// 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
+// 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.
+//
+class CompactHashtableWriter: public StackObj {
+public:
+ class Entry: public CHeapObj<mtSymbol> {
+ Entry* _next;
+ unsigned int _hash;
+ void* _literal;
+
+ public:
+ Entry(unsigned int hash, Symbol *symbol) : _next(NULL), _hash(hash), _literal(symbol) {}
+
+ void *value() {
+ return _literal;
+ }
+ Symbol *symbol() {
+ return (Symbol*)_literal;
+ }
+ unsigned int hash() {
+ return _hash;
+ }
+ Entry *next() {return _next;}
+ void set_next(Entry *p) {_next = p;}
+ }; // class CompactHashtableWriter::Entry
+
+private:
+ static int number_of_buckets(int num_entries);
+
+ const char* _table_name;
+ int _num_entries;
+ int _num_buckets;
+ juint* _bucket_sizes;
+ Entry** _buckets;
+ int _required_bytes;
+ CompactHashtableStats* _stats;
+
+public:
+ // This is called at dump-time only
+ CompactHashtableWriter(const char* table_name, int num_entries, CompactHashtableStats* stats);
+ ~CompactHashtableWriter();
+
+ int get_required_bytes() {
+ return _required_bytes;
+ }
+
+ void add(unsigned int hash, Symbol* symbol) {
+ add(hash, new Entry(hash, symbol));
+ }
+
+private:
+ void add(unsigned int hash, Entry* entry);
+ juint* dump_table(juint* p, juint** first_bucket, NumberSeq* summary);
+ juint* dump_buckets(juint* table, juint* p, NumberSeq* summary);
+
+public:
+ void dump(char** top, char* end);
+};
+
+#define REGULAR_BUCKET_TYPE 0
+#define COMPACT_BUCKET_TYPE 1
+#define TABLEEND_BUCKET_TYPE 3
+#define BUCKET_OFFSET_MASK 0x3FFFFFFF
+#define BUCKET_OFFSET(info) ((info) & BUCKET_OFFSET_MASK)
+#define BUCKET_TYPE_SHIFT 30
+#define BUCKET_TYPE(info) (((info) & ~BUCKET_OFFSET_MASK) >> BUCKET_TYPE_SHIFT)
+#define BUCKET_INFO(offset, type) (((type) << BUCKET_TYPE_SHIFT) | ((offset) & BUCKET_OFFSET_MASK))
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// CompactHashtable is used to stored the CDS archive's symbol 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:
+//
+// uintx base_address;
+// juint num_symbols;
+// juint num_buckets;
+// juint bucket_infos[num_buckets+1]; // bit[31,30]: type; bit[29-0]: offset
+// juint table[]
+//
+// -----------------------------------
+// | base_address | num_symbols |
+// |---------------------------------|
+// | num_buckets | bucket_info0 |
+// |---------------------------------|
+// | bucket_info1 | bucket_info2 |
+// | bucket_info3 ... |
+// | .... | table_end_info |
+// |---------------------------------|
+// | entry0 |
+// | entry1 |
+// | entry2 |
+// | |
+// | ... |
+// -----------------------------------
+//
+// The size of the bucket_info table is 'num_buckets + 1'. Each entry of the
+// bucket_info table is a 32-bit encoding of the bucket type and bucket offset,
+// with the type in the left-most 2-bit and offset in the remaining 30-bit.
+// The last entry is a special type. It contains the offset of the last
+// bucket end. We use that information when traversing the compact table.
+//
+// There are two types of buckets, regular buckets and compact buckets. The
+// 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 compact buckets, each entry has only the 4-byte 'offset' in the table[].
+//
+// See CompactHashtable::lookup() for how the table is searched at runtime.
+// See CompactHashtableWriter::dump() for how the table is written at CDS
+// dump time.
+//
+template <class T, class N> class CompactHashtable VALUE_OBJ_CLASS_SPEC {
+ 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;
+ }
+ }
+
+public:
+ CompactHashtable() {
+ _entry_count = 0;
+ _bucket_count = 0;
+ _table_end_offset = 0;
+ _buckets = 0;
+ }
+ const char* init(const char *buffer);
+
+ // Lookup an entry from the compact table
+ inline T lookup(const N* name, unsigned int hash, int len) {
+ if (_entry_count > 0) {
+ assert(!DumpSharedSpaces, "run-time only");
+ int index = hash % _bucket_count;
+ juint bucket_info = _buckets[index];
+ juint bucket_offset = BUCKET_OFFSET(bucket_info);
+ int bucket_type = BUCKET_TYPE(bucket_info);
+ juint* bucket = _buckets + bucket_offset;
+ 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;
+ }
+ } else {
+ // This is a regular bucket, which has more than one
+ // entries. Each entry is a pair of symbol (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;
+ }
+ }
+ bucket += 2;
+ }
+ }
+ }
+ return NULL;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////
+//
+// Read/Write the contents of a hashtable textual dump (created by
+// SymbolTable::dump).
+// Because the dump file may be big (hundred of MB in extreme cases),
+// we use mmap for fast access when reading it.
+//
+class HashtableTextDump VALUE_OBJ_CLASS_SPEC {
+ int _fd;
+ const char* _base;
+ const char* _p;
+ const char* _end;
+ const char* _filename;
+ size_t _size;
+public:
+ HashtableTextDump(const char* filename);
+ ~HashtableTextDump();
+
+ void quit(const char* err, const char* msg);
+
+ inline int remain() {
+ return (int)(_end - _p);
+ }
+
+ void corrupted(const char *p);
+
+ inline void corrupted_if(bool cond) {
+ if (cond) {
+ corrupted(_p);
+ }
+ }
+
+ bool skip_newline();
+ int skip(char must_be_char);
+ void skip_past(char c);
+ void check_version(const char* ver);
+
+ inline int get_num(char delim) {
+ const char* p = _p;
+ const char* end = _end;
+ int num = 0;
+
+ while (p < end) {
+ char c = *p ++;
+ if ('0' <= c && c <= '9') {
+ num = num * 10 + (c - '0');
+ } else if (c == delim) {
+ _p = p;
+ return num;
+ } else {
+ corrupted(p-1);
+ }
+ }
+ corrupted(_end);
+ ShouldNotReachHere();
+ return 0;
+ }
+
+ int scan_prefix();
+ int scan_prefix2();
+
+ jchar unescape(const char* from, const char* end, int count);
+ void get_utf8(char* utf8_buffer, int utf8_length);
+ static void put_utf8(outputStream* st, const char* utf8_string, int utf8_length);
+};
+
+///////////////////////////////////////////////////////////////////////
+//
+// jcmd command support for symbol table and string table dumping:
+// VM.symboltable -verbose: for dumping the symbol table
+// VM.stringtable -verbose: for dumping the string table
+//
+class VM_DumpHashtable : public VM_Operation {
+private:
+ outputStream* _out;
+ int _which;
+ bool _verbose;
+public:
+ enum {
+ DumpSymbols = 1 << 0,
+ DumpStrings = 1 << 1,
+ DumpSysDict = 1 << 2 // not implemented yet
+ };
+ VM_DumpHashtable(outputStream* out, int which, bool verbose) {
+ _out = out;
+ _which = which;
+ _verbose = verbose;
+ }
+
+ virtual VMOp_Type type() const { return VMOp_DumpHashtable; }
+
+ virtual void doit() {
+ switch (_which) {
+ case DumpSymbols:
+ SymbolTable::dump(_out, _verbose);
+ break;
+ case DumpStrings:
+ StringTable::dump(_out, _verbose);
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ }
+};
+
+class SymboltableDCmd : public DCmdWithParser {
+protected:
+ DCmdArgument<bool> _verbose;
+public:
+ SymboltableDCmd(outputStream* output, bool heap);
+ static const char* name() {
+ return "VM.symboltable";
+ }
+ static const char* description() {
+ return "Dump symbol table.";
+ }
+ static const char* impact() {
+ return "Medium: Depends on Java content.";
+ }
+ static const JavaPermission permission() {
+ JavaPermission p = {"java.lang.management.ManagementPermission",
+ "monitor", NULL};
+ return p;
+ }
+ static int num_arguments();
+ virtual void execute(DCmdSource source, TRAPS);
+};
+
+class StringtableDCmd : public DCmdWithParser {
+protected:
+ DCmdArgument<bool> _verbose;
+public:
+ StringtableDCmd(outputStream* output, bool heap);
+ static const char* name() {
+ return "VM.stringtable";
+ }
+ static const char* description() {
+ return "Dump string table.";
+ }
+ static const char* impact() {
+ return "Medium: Depends on Java content.";
+ }
+ static const JavaPermission permission() {
+ JavaPermission p = {"java.lang.management.ManagementPermission",
+ "monitor", NULL};
+ return p;
+ }
+ static int num_arguments();
+ virtual void execute(DCmdSource source, TRAPS);
+};
+
+#endif // SHARE_VM_CLASSFILE_COMPACTHASHTABLE_HPP
--- a/hotspot/src/share/vm/classfile/stringTable.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
+#include "classfile/compactHashtable.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
@@ -379,8 +380,36 @@
}
}
-void StringTable::dump(outputStream* st) {
- the_table()->dump_table(st, "StringTable");
+void StringTable::dump(outputStream* st, bool verbose) {
+ if (!verbose) {
+ the_table()->dump_table(st, "StringTable");
+ } else {
+ Thread* THREAD = Thread::current();
+ st->print_cr("VERSION: 1.1");
+ for (int i = 0; i < the_table()->table_size(); ++i) {
+ HashtableEntry<oop, mtSymbol>* p = the_table()->bucket(i);
+ for ( ; p != NULL; p = p->next()) {
+ oop s = p->literal();
+ typeArrayOop value = java_lang_String::value(s);
+ int offset = java_lang_String::offset(s);
+ int length = java_lang_String::length(s);
+
+ if (length <= 0) {
+ st->print("%d: ", length);
+ } else {
+ ResourceMark rm(THREAD);
+ jchar* chars = (jchar*)value->char_at_addr(offset);
+ int utf8_length = UNICODE::utf8_length(chars, length);
+ char* utf8_string = NEW_RESOURCE_ARRAY(char, utf8_length + 1);
+ UNICODE::convert_to_utf8(chars, length, utf8_string);
+
+ st->print("%d: ", utf8_length);
+ HashtableTextDump::put_utf8(st, utf8_string, utf8_length);
+ }
+ st->cr();
+ }
+ }
+ }
}
StringTable::VerifyRetTypes StringTable::compare_entries(
@@ -558,3 +587,28 @@
_needs_rehashing = false;
_the_table = new_table;
}
+
+// Utility for dumping strings
+StringtableDCmd::StringtableDCmd(outputStream* output, bool heap) :
+ DCmdWithParser(output, heap),
+ _verbose("-verbose", "Dump the content of each string in the table",
+ "BOOLEAN", false, "false") {
+ _dcmdparser.add_dcmd_option(&_verbose);
+}
+
+void StringtableDCmd::execute(DCmdSource source, TRAPS) {
+ VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpStrings,
+ _verbose.value());
+ VMThread::execute(&dumper);
+}
+
+int StringtableDCmd::num_arguments() {
+ ResourceMark rm;
+ StringtableDCmd* dcmd = new StringtableDCmd(NULL, false);
+ if (dcmd != NULL) {
+ DCmdMark mark(dcmd);
+ return dcmd->_dcmdparser.num_arguments();
+ } else {
+ return 0;
+ }
+}
--- a/hotspot/src/share/vm/classfile/stringTable.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/classfile/stringTable.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -118,7 +118,7 @@
// Debugging
static void verify();
- static void dump(outputStream* st);
+ static void dump(outputStream* st, bool verbose=false);
enum VerifyMesgModes {
_verify_quietly = 0,
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
+#include "classfile/compactHashtable.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
@@ -47,6 +48,9 @@
// Static arena for symbols that are not deallocated
Arena* SymbolTable::_arena = NULL;
bool SymbolTable::_needs_rehashing = false;
+bool SymbolTable::_lookup_shared_first = false;
+
+CompactHashtable<Symbol*, char> SymbolTable::_shared_table;
Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS) {
assert (len <= Symbol::max_length(), "should be checked by caller");
@@ -186,8 +190,8 @@
// Lookup a symbol in a bucket.
-Symbol* SymbolTable::lookup(int index, const char* name,
- int len, unsigned int hash) {
+Symbol* SymbolTable::lookup_dynamic(int index, const char* name,
+ int len, unsigned int hash) {
int count = 0;
for (HashtableEntry<Symbol*, mtSymbol>* e = bucket(index); e != NULL; e = e->next()) {
count++; // count all entries in this bucket, not just ones with same hash
@@ -207,6 +211,34 @@
return NULL;
}
+Symbol* SymbolTable::lookup_shared(const char* name,
+ int len, unsigned int hash) {
+ return _shared_table.lookup(name, hash, len);
+}
+
+Symbol* SymbolTable::lookup(int index, const char* name,
+ int len, unsigned int hash) {
+ Symbol* sym;
+ if (_lookup_shared_first) {
+ sym = lookup_shared(name, len, hash);
+ if (sym != NULL) {
+ return sym;
+ }
+ _lookup_shared_first = false;
+ return lookup_dynamic(index, name, len, hash);
+ } else {
+ sym = lookup_dynamic(index, name, len, hash);
+ if (sym != NULL) {
+ return sym;
+ }
+ sym = lookup_shared(name, len, hash);
+ if (sym != NULL) {
+ _lookup_shared_first = true;
+ }
+ return sym;
+ }
+}
+
// Pick hashing algorithm.
unsigned int SymbolTable::hash_symbol(const char* s, int len) {
return use_alternate_hashcode() ?
@@ -483,10 +515,56 @@
}
}
-void SymbolTable::dump(outputStream* st) {
- the_table()->dump_table(st, "SymbolTable");
+void SymbolTable::dump(outputStream* st, bool verbose) {
+ if (!verbose) {
+ the_table()->dump_table(st, "SymbolTable");
+ } else {
+ st->print_cr("VERSION: 1.0");
+ for (int i = 0; i < the_table()->table_size(); ++i) {
+ HashtableEntry<Symbol*, mtSymbol>* p = the_table()->bucket(i);
+ for ( ; p != NULL; p = p->next()) {
+ Symbol* s = (Symbol*)(p->literal());
+ const char* utf8_string = (const char*)s->bytes();
+ int utf8_length = s->utf8_length();
+ st->print("%d %d: ", utf8_length, s->refcount());
+ HashtableTextDump::put_utf8(st, utf8_string, utf8_length);
+ st->cr();
+ }
+ }
+ }
}
+bool SymbolTable::copy_compact_table(char** top, char*end) {
+#if INCLUDE_CDS
+ CompactHashtableWriter ch_table("symbol", the_table()->number_of_entries(),
+ &MetaspaceShared::stats()->symbol);
+ if (*top + ch_table.get_required_bytes() > end) {
+ // not enough space left
+ return false;
+ }
+
+ for (int i = 0; i < the_table()->table_size(); ++i) {
+ HashtableEntry<Symbol*, mtSymbol>* p = the_table()->bucket(i);
+ for ( ; p != NULL; p = p->next()) {
+ Symbol* s = (Symbol*)(p->literal());
+ unsigned int fixed_hash = hash_symbol((char*)s->bytes(), s->utf8_length());
+ assert(fixed_hash == p->hash(), "must not rehash during dumping");
+ ch_table.add(fixed_hash, s);
+ }
+ }
+
+ char* old_top = *top;
+ ch_table.dump(top, end);
+
+ *top = (char*)align_pointer_up(*top, sizeof(void*));
+#endif
+ return true;
+}
+
+const char* SymbolTable::init_shared_table(const char* buffer) {
+ const char* end = _shared_table.init(buffer);
+ return (const char*)align_pointer_up(end, sizeof(void*));
+}
//---------------------------------------------------------------------------
// Non-product code
@@ -574,3 +652,29 @@
}
}
#endif // PRODUCT
+
+
+// Utility for dumping symbols
+SymboltableDCmd::SymboltableDCmd(outputStream* output, bool heap) :
+ DCmdWithParser(output, heap),
+ _verbose("-verbose", "Dump the content of each symbol in the table",
+ "BOOLEAN", false, "false") {
+ _dcmdparser.add_dcmd_option(&_verbose);
+}
+
+void SymboltableDCmd::execute(DCmdSource source, TRAPS) {
+ VM_DumpHashtable dumper(output(), VM_DumpHashtable::DumpSymbols,
+ _verbose.value());
+ VMThread::execute(&dumper);
+}
+
+int SymboltableDCmd::num_arguments() {
+ ResourceMark rm;
+ SymboltableDCmd* dcmd = new SymboltableDCmd(NULL, false);
+ if (dcmd != NULL) {
+ DCmdMark mark(dcmd);
+ return dcmd->_dcmdparser.num_arguments();
+ } else {
+ return 0;
+ }
+}
--- a/hotspot/src/share/vm/classfile/symbolTable.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/classfile/symbolTable.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -73,6 +73,8 @@
operator Symbol*() { return _temp; }
};
+template <class T, class N> class CompactHashtable;
+
class SymbolTable : public RehashableHashtable<Symbol*, mtSymbol> {
friend class VMStructs;
friend class ClassFileParser;
@@ -83,11 +85,15 @@
// Set if one bucket is out of balance due to hash algorithm deficiency
static bool _needs_rehashing;
+ static bool _lookup_shared_first;
// For statistics
static int _symbols_removed;
static int _symbols_counted;
+ // shared symbol table.
+ static CompactHashtable<Symbol*, char> _shared_table;
+
Symbol* allocate_symbol(const u1* name, int len, bool c_heap, TRAPS); // Assumes no characters larger than 0x7F
// Adding elements
@@ -106,6 +112,8 @@
add(loader_data, cp, names_count, name, lengths, cp_indices, hashValues, THREAD);
}
+ static Symbol* lookup_shared(const char* name, int len, unsigned int hash);
+ Symbol* lookup_dynamic(int index, const char* name, int len, unsigned int hash);
Symbol* lookup(int index, const char* name, int len, unsigned int hash);
SymbolTable()
@@ -144,20 +152,6 @@
initialize_symbols(symbol_alloc_arena_size);
}
- static void create_table(HashtableBucket<mtSymbol>* t, int length,
- int number_of_entries) {
- assert(_the_table == NULL, "One symbol table allowed.");
-
- // If CDS archive used a different symbol table size, use that size instead
- // which is better than giving an error.
- SymbolTableSize = length/bucket_size();
-
- _the_table = new SymbolTable(t, number_of_entries);
- // if CDS give symbol table a default arena size since most symbols
- // are already allocated in the shared misc section.
- initialize_symbols();
- }
-
static unsigned int hash_symbol(const char* s, int len);
static Symbol* lookup(const char* name, int len, TRAPS);
@@ -230,18 +224,12 @@
// Debugging
static void verify();
- static void dump(outputStream* st);
+ static void dump(outputStream* st, bool verbose=false);
+ static void read(const char* filename, TRAPS);
// Sharing
- static void copy_buckets(char** top, char*end) {
- the_table()->Hashtable<Symbol*, mtSymbol>::copy_buckets(top, end);
- }
- static void copy_table(char** top, char*end) {
- the_table()->Hashtable<Symbol*, mtSymbol>::copy_table(top, end);
- }
- static void reverse(void* boundary = NULL) {
- the_table()->Hashtable<Symbol*, mtSymbol>::reverse(boundary);
- }
+ static bool copy_compact_table(char** top, char* end);
+ static const char* init_shared_table(const char* buffer);
// Rehash the symbol table if it gets out of balance
static void rehash_table();
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -32,6 +32,7 @@
#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/interpreter.hpp"
@@ -1627,7 +1628,7 @@
// Note: must be done *after* linking k into the hierarchy (was bug 12/9/97)
// Also, first reinitialize vtable because it may have gotten out of synch
// while the new class wasn't connected to the class hierarchy.
- Universe::flush_dependents_on(k);
+ CodeCache::flush_dependents_on(k);
}
// ----------------------------------------------------------------------------
--- a/hotspot/src/share/vm/classfile/verifier.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/classfile/verifier.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -2477,8 +2477,7 @@
// of the current class.
VerificationType objectref_type = new_class_type;
if (name_in_supers(ref_class_type.name(), current_class())) {
- Klass* ref_klass = load_class(
- ref_class_type.name(), CHECK_VERIFY(this));
+ Klass* ref_klass = load_class(ref_class_type.name(), CHECK);
Method* m = InstanceKlass::cast(ref_klass)->uncached_lookup_method(
vmSymbols::object_initializer_name(),
cp->signature_ref_at(bcs->get_index_u2()),
--- a/hotspot/src/share/vm/code/codeCache.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/code/codeCache.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -1005,6 +1005,117 @@
}
}
+// Flushes compiled methods dependent on dependee.
+void CodeCache::flush_dependents_on(instanceKlassHandle dependee) {
+ assert_lock_strong(Compile_lock);
+
+ if (number_of_nmethods_with_dependencies() == 0) return;
+
+ // CodeCache can only be updated by a thread_in_VM and they will all be
+ // stopped during the safepoint so CodeCache will be safe to update without
+ // holding the CodeCache_lock.
+
+ KlassDepChange changes(dependee);
+
+ // Compute the dependent nmethods
+ if (mark_for_deoptimization(changes) > 0) {
+ // At least one nmethod has been marked for deoptimization
+ VM_Deoptimize op;
+ VMThread::execute(&op);
+ }
+}
+
+// Flushes compiled methods dependent on a particular CallSite
+// instance when its target is different than the given MethodHandle.
+void CodeCache::flush_dependents_on(Handle call_site, Handle method_handle) {
+ assert_lock_strong(Compile_lock);
+
+ if (number_of_nmethods_with_dependencies() == 0) return;
+
+ // CodeCache can only be updated by a thread_in_VM and they will all be
+ // stopped during the safepoint so CodeCache will be safe to update without
+ // holding the CodeCache_lock.
+
+ CallSiteDepChange changes(call_site(), method_handle());
+
+ // Compute the dependent nmethods that have a reference to a
+ // CallSite object. We use InstanceKlass::mark_dependent_nmethod
+ // directly instead of CodeCache::mark_for_deoptimization because we
+ // want dependents on the call site class only not all classes in
+ // the ContextStream.
+ int marked = 0;
+ {
+ MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+ InstanceKlass* call_site_klass = InstanceKlass::cast(call_site->klass());
+ marked = call_site_klass->mark_dependent_nmethods(changes);
+ }
+ if (marked > 0) {
+ // At least one nmethod has been marked for deoptimization
+ VM_Deoptimize op;
+ VMThread::execute(&op);
+ }
+}
+
+#ifdef HOTSWAP
+// Flushes compiled methods dependent on dependee in the evolutionary sense
+void CodeCache::flush_evol_dependents_on(instanceKlassHandle ev_k_h) {
+ // --- Compile_lock is not held. However we are at a safepoint.
+ assert_locked_or_safepoint(Compile_lock);
+ if (number_of_nmethods_with_dependencies() == 0) return;
+
+ // CodeCache can only be updated by a thread_in_VM and they will all be
+ // stopped during the safepoint so CodeCache will be safe to update without
+ // holding the CodeCache_lock.
+
+ // Compute the dependent nmethods
+ if (mark_for_evol_deoptimization(ev_k_h) > 0) {
+ // At least one nmethod has been marked for deoptimization
+
+ // All this already happens inside a VM_Operation, so we'll do all the work here.
+ // Stuff copied from VM_Deoptimize and modified slightly.
+
+ // We do not want any GCs to happen while we are in the middle of this VM operation
+ ResourceMark rm;
+ DeoptimizationMarker dm;
+
+ // Deoptimize all activations depending on marked nmethods
+ Deoptimization::deoptimize_dependents();
+
+ // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
+ make_marked_nmethods_not_entrant();
+ }
+}
+#endif // HOTSWAP
+
+
+// Flushes compiled methods dependent on dependee
+void CodeCache::flush_dependents_on_method(methodHandle m_h) {
+ // --- Compile_lock is not held. However we are at a safepoint.
+ assert_locked_or_safepoint(Compile_lock);
+
+ // CodeCache can only be updated by a thread_in_VM and they will all be
+ // stopped dring the safepoint so CodeCache will be safe to update without
+ // holding the CodeCache_lock.
+
+ // Compute the dependent nmethods
+ if (mark_for_deoptimization(m_h()) > 0) {
+ // At least one nmethod has been marked for deoptimization
+
+ // All this already happens inside a VM_Operation, so we'll do all the work here.
+ // Stuff copied from VM_Deoptimize and modified slightly.
+
+ // We do not want any GCs to happen while we are in the middle of this VM operation
+ ResourceMark rm;
+ DeoptimizationMarker dm;
+
+ // Deoptimize all activations depending on marked nmethods
+ Deoptimization::deoptimize_dependents();
+
+ // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
+ make_marked_nmethods_not_entrant();
+ }
+}
+
void CodeCache::verify() {
assert_locked_or_safepoint(CodeCache_lock);
FOR_ALL_HEAPS(heap) {
--- a/hotspot/src/share/vm/code/codeCache.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/code/codeCache.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -209,16 +209,28 @@
static void verify_icholder_relocations();
// Deoptimization
+ private:
static int mark_for_deoptimization(DepChange& changes);
#ifdef HOTSWAP
static int mark_for_evol_deoptimization(instanceKlassHandle dependee);
#endif // HOTSWAP
+ public:
static void mark_all_nmethods_for_deoptimization();
static int mark_for_deoptimization(Method* dependee);
static void make_marked_nmethods_zombies();
static void make_marked_nmethods_not_entrant();
+ // Flushing and deoptimization
+ static void flush_dependents_on(instanceKlassHandle dependee);
+ static void flush_dependents_on(Handle call_site, Handle method_handle);
+#ifdef HOTSWAP
+ // Flushing and deoptimization in case of evolution
+ static void flush_evol_dependents_on(instanceKlassHandle dependee);
+#endif // HOTSWAP
+ // Support for fullspeed debugging
+ static void flush_dependents_on_method(methodHandle dependee);
+
// tells how many nmethods have dependencies
static int number_of_nmethods_with_dependencies();
--- a/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1Allocator.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -99,8 +99,8 @@
}
if (ResizePLAB) {
- _g1h->_survivor_plab_stats.adjust_desired_plab_sz(no_of_gc_workers);
- _g1h->_old_plab_stats.adjust_desired_plab_sz(no_of_gc_workers);
+ _g1h->alloc_buffer_stats(InCSetState::Young)->adjust_desired_plab_sz(no_of_gc_workers);
+ _g1h->alloc_buffer_stats(InCSetState::Old)->adjust_desired_plab_sz(no_of_gc_workers);
}
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -2068,7 +2068,7 @@
}
void G1CollectedHeap::clear_humongous_is_live_table() {
- guarantee(G1ReclaimDeadHumongousObjectsAtYoungGC, "Should only be called if true");
+ guarantee(G1EagerReclaimHumongousObjects, "Should only be called if true");
_humongous_is_live.clear();
}
@@ -3485,8 +3485,24 @@
private:
size_t _total_humongous;
size_t _candidate_humongous;
+
+ DirtyCardQueue _dcq;
+
+ bool humongous_region_is_candidate(uint index) {
+ HeapRegion* region = G1CollectedHeap::heap()->region_at(index);
+ assert(region->is_starts_humongous(), "Must start a humongous object");
+ HeapRegionRemSet* const rset = region->rem_set();
+ bool const allow_stale_refs = G1EagerReclaimHumongousObjectsWithStaleRefs;
+ return !oop(region->bottom())->is_objArray() &&
+ ((allow_stale_refs && rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries)) ||
+ (!allow_stale_refs && rset->is_empty()));
+ }
+
public:
- RegisterHumongousWithInCSetFastTestClosure() : _total_humongous(0), _candidate_humongous(0) {
+ RegisterHumongousWithInCSetFastTestClosure()
+ : _total_humongous(0),
+ _candidate_humongous(0),
+ _dcq(&JavaThread::dirty_card_queue_set()) {
}
virtual bool doHeapRegion(HeapRegion* r) {
@@ -3496,11 +3512,29 @@
G1CollectedHeap* g1h = G1CollectedHeap::heap();
uint region_idx = r->hrm_index();
- bool is_candidate = !g1h->humongous_region_is_always_live(region_idx);
- // Is_candidate already filters out humongous regions with some remembered set.
- // This will not lead to humongous object that we mistakenly keep alive because
- // during young collection the remembered sets will only be added to.
+ bool is_candidate = humongous_region_is_candidate(region_idx);
+ // Is_candidate already filters out humongous object with large remembered sets.
+ // If we have a humongous object with a few remembered sets, we simply flush these
+ // remembered set entries into the DCQS. That will result in automatic
+ // re-evaluation of their remembered set entries during the following evacuation
+ // phase.
if (is_candidate) {
+ if (!r->rem_set()->is_empty()) {
+ guarantee(r->rem_set()->occupancy_less_or_equal_than(G1RSetSparseRegionEntries),
+ "Found a not-small remembered set here. This is inconsistent with previous assumptions.");
+ G1SATBCardTableLoggingModRefBS* bs = g1h->g1_barrier_set();
+ HeapRegionRemSetIterator hrrs(r->rem_set());
+ size_t card_index;
+ while (hrrs.has_next(card_index)) {
+ jbyte* card_ptr = (jbyte*)bs->byte_for_index(card_index);
+ if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
+ *card_ptr = CardTableModRefBS::dirty_card_val();
+ _dcq.enqueue(card_ptr);
+ }
+ }
+ r->rem_set()->clear_locked();
+ }
+ assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty.");
g1h->register_humongous_region_with_in_cset_fast_test(region_idx);
_candidate_humongous++;
}
@@ -3511,23 +3545,32 @@
size_t total_humongous() const { return _total_humongous; }
size_t candidate_humongous() const { return _candidate_humongous; }
+
+ void flush_rem_set_entries() { _dcq.flush(); }
};
void G1CollectedHeap::register_humongous_regions_with_in_cset_fast_test() {
- if (!G1ReclaimDeadHumongousObjectsAtYoungGC) {
- g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0, 0);
+ if (!G1EagerReclaimHumongousObjects) {
+ g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(0.0, 0, 0);
return;
}
+ double time = os::elapsed_counter();
RegisterHumongousWithInCSetFastTestClosure cl;
heap_region_iterate(&cl);
- g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(cl.total_humongous(),
+
+ time = ((double)(os::elapsed_counter() - time) / os::elapsed_frequency()) * 1000.0;
+ g1_policy()->phase_times()->record_fast_reclaim_humongous_stats(time,
+ cl.total_humongous(),
cl.candidate_humongous());
_has_humongous_reclaim_candidates = cl.candidate_humongous() > 0;
- if (_has_humongous_reclaim_candidates || G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
+ if (_has_humongous_reclaim_candidates || G1TraceEagerReclaimHumongousObjects) {
clear_humongous_is_live_table();
}
+
+ // Finally flush all remembered set entries to re-check into the global DCQS.
+ cl.flush_rem_set_entries();
}
void
@@ -6140,22 +6183,20 @@
// are completely up-to-date wrt to references to the humongous object.
//
// Other implementation considerations:
- // - never consider object arrays: while they are a valid target, they have not
- // been observed to be used as temporary objects.
- // - they would also pose considerable effort for cleaning up the the remembered
- // sets.
- // While this cleanup is not strictly necessary to be done (or done instantly),
- // given that their occurrence is very low, this saves us this additional
- // complexity.
+ // - never consider object arrays at this time because they would pose
+ // considerable effort for cleaning up the the remembered sets. This is
+ // required because stale remembered sets might reference locations that
+ // are currently allocated into.
uint region_idx = r->hrm_index();
if (g1h->humongous_is_live(region_idx) ||
g1h->humongous_region_is_always_live(region_idx)) {
- if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
- gclog_or_tty->print_cr("Live humongous %d region %d size "SIZE_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
- r->is_humongous(),
+ if (G1TraceEagerReclaimHumongousObjects) {
+ gclog_or_tty->print_cr("Live humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
region_idx,
obj->size()*HeapWordSize,
+ r->bottom(),
+ r->region_num(),
r->rem_set()->occupied(),
r->rem_set()->strong_code_roots_list_length(),
next_bitmap->isMarked(r->bottom()),
@@ -6171,12 +6212,11 @@
err_msg("Eagerly reclaiming object arrays is not supported, but the object "PTR_FORMAT" is.",
r->bottom()));
- if (G1TraceReclaimDeadHumongousObjectsAtYoungGC) {
- gclog_or_tty->print_cr("Reclaim humongous region %d size "SIZE_FORMAT" start "PTR_FORMAT" region %d length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
- r->is_humongous(),
+ if (G1TraceEagerReclaimHumongousObjects) {
+ gclog_or_tty->print_cr("Dead humongous region %u size "SIZE_FORMAT" start "PTR_FORMAT" length "UINT32_FORMAT" with remset "SIZE_FORMAT" code roots "SIZE_FORMAT" is marked %d live-other %d obj array %d",
+ region_idx,
obj->size()*HeapWordSize,
r->bottom(),
- region_idx,
r->region_num(),
r->rem_set()->occupied(),
r->rem_set()->strong_code_roots_list_length(),
@@ -6213,8 +6253,8 @@
void G1CollectedHeap::eagerly_reclaim_humongous_regions() {
assert_at_safepoint(true);
- if (!G1ReclaimDeadHumongousObjectsAtYoungGC ||
- (!_has_humongous_reclaim_candidates && !G1TraceReclaimDeadHumongousObjectsAtYoungGC)) {
+ if (!G1EagerReclaimHumongousObjects ||
+ (!_has_humongous_reclaim_candidates && !G1TraceEagerReclaimHumongousObjects)) {
g1_policy()->phase_times()->record_fast_reclaim_humongous_time_ms(0.0, 0);
return;
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -186,32 +186,14 @@
friend class SurvivorGCAllocRegion;
friend class OldGCAllocRegion;
friend class G1Allocator;
- friend class G1DefaultAllocator;
- friend class G1ResManAllocator;
// Closures used in implementation.
- template <G1Barrier barrier, G1Mark do_mark_object>
- friend class G1ParCopyClosure;
- friend class G1IsAliveClosure;
- friend class G1EvacuateFollowersClosure;
friend class G1ParScanThreadState;
- friend class G1ParScanClosureSuper;
- friend class G1ParEvacuateFollowersClosure;
friend class G1ParTask;
friend class G1ParGCAllocator;
- friend class G1DefaultParGCAllocator;
- friend class G1FreeGarbageRegionClosure;
- friend class RefineCardTableEntryClosure;
friend class G1PrepareCompactClosure;
- friend class RegionSorter;
- friend class RegionResetter;
- friend class CountRCClosure;
- friend class EvacPopObjClosure;
- friend class G1ParCleanupCTTask;
- friend class G1FreeHumongousRegionClosure;
// Other related classes.
- friend class G1MarkSweep;
friend class HeapRegionClaimer;
// Testing classes.
@@ -659,6 +641,9 @@
// Returns whether the given region (which must be a humongous (start) region)
// is to be considered conservatively live regardless of any other conditions.
bool humongous_region_is_always_live(uint index);
+ // Returns whether the given region (which must be a humongous (start) region)
+ // is considered a candidate for eager reclamation.
+ bool humongous_region_is_candidate(uint index);
// Register the given region to be part of the collection set.
inline void register_humongous_region_with_in_cset_fast_test(uint index);
// Register regions with humongous objects (actually on the start region) in
--- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -344,11 +344,14 @@
_last_redirty_logged_cards_time_ms.print(3, "Parallel Redirty");
_last_redirty_logged_cards_processed_cards.print(3, "Redirtied Cards");
}
- if (G1ReclaimDeadHumongousObjectsAtYoungGC) {
- print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
+ if (G1EagerReclaimHumongousObjects) {
+ print_stats(2, "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms);
if (G1Log::finest()) {
print_stats(3, "Humongous Total", _cur_fast_reclaim_humongous_total);
print_stats(3, "Humongous Candidate", _cur_fast_reclaim_humongous_candidates);
+ }
+ print_stats(2, "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms);
+ if (G1Log::finest()) {
print_stats(3, "Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed);
}
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -157,6 +157,7 @@
double _recorded_non_young_free_cset_time_ms;
double _cur_fast_reclaim_humongous_time_ms;
+ double _cur_fast_reclaim_humongous_register_time_ms;
size_t _cur_fast_reclaim_humongous_total;
size_t _cur_fast_reclaim_humongous_candidates;
size_t _cur_fast_reclaim_humongous_reclaimed;
@@ -283,7 +284,8 @@
_recorded_non_young_free_cset_time_ms = time_ms;
}
- void record_fast_reclaim_humongous_stats(size_t total, size_t candidates) {
+ void record_fast_reclaim_humongous_stats(double time_ms, size_t total, size_t candidates) {
+ _cur_fast_reclaim_humongous_register_time_ms = time_ms;
_cur_fast_reclaim_humongous_total = total;
_cur_fast_reclaim_humongous_candidates = candidates;
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -270,10 +270,14 @@
product(uintx, G1MixedGCCountTarget, 8, \
"The target number of mixed GCs after a marking cycle.") \
\
- experimental(bool, G1ReclaimDeadHumongousObjectsAtYoungGC, true, \
+ experimental(bool, G1EagerReclaimHumongousObjects, true, \
"Try to reclaim dead large objects at every young GC.") \
\
- experimental(bool, G1TraceReclaimDeadHumongousObjectsAtYoungGC, false, \
+ experimental(bool, G1EagerReclaimHumongousObjectsWithStaleRefs, true, \
+ "Try to reclaim dead large objects that have a few stale " \
+ "references at every young GC.") \
+ \
+ experimental(bool, G1TraceEagerReclaimHumongousObjects, false, \
"Print some information about large object liveness " \
"at every young GC.") \
\
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -681,6 +681,18 @@
clear_fcc();
}
+bool OtherRegionsTable::occupancy_less_or_equal_than(size_t limit) const {
+ if (limit <= (size_t)G1RSetSparseRegionEntries) {
+ return occ_coarse() == 0 && _first_all_fine_prts == NULL && occ_sparse() <= limit;
+ } else {
+ // Current uses of this method may only use values less than G1RSetSparseRegionEntries
+ // for the limit. The solution, comparing against occupied() would be too slow
+ // at this time.
+ Unimplemented();
+ return false;
+ }
+}
+
bool OtherRegionsTable::is_empty() const {
return occ_sparse() == 0 && occ_coarse() == 0 && _first_all_fine_prts == NULL;
}
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -183,6 +183,10 @@
// Returns whether the remembered set contains the given reference.
bool contains_reference(OopOrNarrowOopStar from) const;
+ // Returns whether this remembered set (and all sub-sets) have an occupancy
+ // that is less or equal than the given occupancy.
+ bool occupancy_less_or_equal_than(size_t limit) const;
+
// Removes any entries shown by the given bitmaps to contain only dead
// objects. Not thread safe.
// Set bits in the bitmaps indicate that the given region or card is live.
@@ -261,6 +265,10 @@
return (strong_code_roots_list_length() == 0) && _other_regions.is_empty();
}
+ bool occupancy_less_or_equal_than(size_t occ) const {
+ return (strong_code_roots_list_length() == 0) && _other_regions.occupancy_less_or_equal_than(occ);
+ }
+
size_t occupied() {
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
return occupied_locked();
--- a/hotspot/src/share/vm/memory/metaspace.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2014, 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
@@ -422,7 +422,7 @@
bool large_pages = false; // No large pages when dumping the CDS archive.
char* shared_base = (char*)align_ptr_up((char*)SharedBaseAddress, Metaspace::reserve_alignment());
- _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages, shared_base, 0);
+ _rs = ReservedSpace(bytes, Metaspace::reserve_alignment(), large_pages, shared_base);
if (_rs.is_reserved()) {
assert(shared_base == 0 || _rs.base() == shared_base, "should match");
} else {
@@ -3025,7 +3025,7 @@
ReservedSpace metaspace_rs = ReservedSpace(compressed_class_space_size(),
_reserve_alignment,
large_pages,
- requested_addr, 0);
+ requested_addr);
if (!metaspace_rs.is_reserved()) {
#if INCLUDE_CDS
if (UseSharedSpaces) {
@@ -3039,7 +3039,7 @@
can_use_cds_with_metaspace_addr(addr + increment, cds_base)) {
addr = addr + increment;
metaspace_rs = ReservedSpace(compressed_class_space_size(),
- _reserve_alignment, large_pages, addr, 0);
+ _reserve_alignment, large_pages, addr);
}
}
#endif
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -48,6 +48,8 @@
ReservedSpace* MetaspaceShared::_shared_rs = NULL;
+MetaspaceSharedStats MetaspaceShared::_stats;
+
bool MetaspaceShared::_link_classes_made_progress;
bool MetaspaceShared::_check_classes_made_progress;
bool MetaspaceShared::_has_error_classes;
@@ -259,7 +261,7 @@
#define SHAREDSPACE_OBJ_TYPES_DO(f) \
METASPACE_OBJ_TYPES_DO(f) \
f(SymbolHashentry) \
- f(SymbolBuckets) \
+ f(SymbolBucket) \
f(Other)
#define SHAREDSPACE_OBJ_TYPE_DECLARE(name) name ## Type,
@@ -315,18 +317,16 @@
int other_bytes = md_all + mc_all;
// Calculate size of data that was not allocated by Metaspace::allocate()
- int symbol_count = _counts[RO][MetaspaceObj::SymbolType];
- int symhash_bytes = symbol_count * sizeof (HashtableEntry<Symbol*, mtSymbol>);
- int symbuck_count = SymbolTable::the_table()->table_size();
- int symbuck_bytes = symbuck_count * sizeof(HashtableBucket<mtSymbol>);
+ MetaspaceSharedStats *stats = MetaspaceShared::stats();
- _counts[RW][SymbolHashentryType] = symbol_count;
- _bytes [RW][SymbolHashentryType] = symhash_bytes;
- other_bytes -= symhash_bytes;
+ // symbols
+ _counts[RW][SymbolHashentryType] = stats->symbol.hashentry_count;
+ _bytes [RW][SymbolHashentryType] = stats->symbol.hashentry_bytes;
+ other_bytes -= stats->symbol.hashentry_bytes;
- _counts[RW][SymbolBucketsType] = symbuck_count;
- _bytes [RW][SymbolBucketsType] = symbuck_bytes;
- other_bytes -= symbuck_bytes;
+ _counts[RW][SymbolBucketType] = stats->symbol.bucket_count;
+ _bytes [RW][SymbolBucketType] = stats->symbol.bucket_bytes;
+ other_bytes -= stats->symbol.bucket_bytes;
// TODO: count things like dictionary, vtable, etc
_bytes[RW][OtherType] = other_bytes;
@@ -424,6 +424,13 @@
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
void doit(); // outline because gdb sucks
+
+private:
+ void handle_misc_data_space_failure(bool success) {
+ if (!success) {
+ report_out_of_shared_space(SharedMiscData);
+ }
+ }
}; // class VM_PopulateDumpSharedSpace
@@ -517,9 +524,8 @@
// buckets first [read-write], then copy the linked lists of entries
// [read-only].
- SymbolTable::reverse(md_top);
NOT_PRODUCT(SymbolTable::verify());
- SymbolTable::copy_buckets(&md_top, md_end);
+ handle_misc_data_space_failure(SymbolTable::copy_compact_table(&md_top, md_end));
SystemDictionary::reverse();
SystemDictionary::copy_buckets(&md_top, md_end);
@@ -528,7 +534,6 @@
ClassLoader::copy_package_info_buckets(&md_top, md_end);
ClassLoader::verify();
- SymbolTable::copy_table(&md_top, md_end);
SystemDictionary::copy_table(&md_top, md_end);
ClassLoader::verify();
ClassLoader::copy_package_info_table(&md_top, md_end);
@@ -1000,17 +1005,12 @@
buffer += sizeof(intptr_t);
buffer += vtable_size;
- // Create the symbol table using the bucket array at this spot in the
- // misc data space. Since the symbol table is often modified, this
- // region (of mapped pages) will be copy-on-write.
+ // Create the shared symbol table using the bucket array 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).
- int symbolTableLen = *(intptr_t*)buffer;
- buffer += sizeof(intptr_t);
- int number_of_entries = *(intptr_t*)buffer;
- buffer += sizeof(intptr_t);
- SymbolTable::create_table((HashtableBucket<mtSymbol>*)buffer, symbolTableLen,
- number_of_entries);
- buffer += symbolTableLen;
+ buffer = (char*)SymbolTable::init_shared_table(buffer);
+ SymbolTable::create_table();
// Create the shared dictionary using the bucket array at this spot in
// the misc data space. Since the shared dictionary table is never
@@ -1019,7 +1019,7 @@
int sharedDictionaryLen = *(intptr_t*)buffer;
buffer += sizeof(intptr_t);
- number_of_entries = *(intptr_t*)buffer;
+ int number_of_entries = *(intptr_t*)buffer;
buffer += sizeof(intptr_t);
SystemDictionary::set_shared_dictionary((HashtableBucket<mtClass>*)buffer,
sharedDictionaryLen,
@@ -1041,18 +1041,10 @@
ClassLoader::verify();
// The following data in the shared misc data region are the linked
- // list elements (HashtableEntry objects) for the symbol table, string
- // table, and shared dictionary. The heap objects referred to by the
- // symbol table, string table, and shared dictionary are permanent and
- // unmovable. Since new entries added to the string and symbol tables
- // are always added at the beginning of the linked lists, THESE LINKED
- // LIST ELEMENTS ARE READ-ONLY.
+ // list elements (HashtableEntry objects) for the shared dictionary
+ // and package info table.
- int len = *(intptr_t*)buffer; // skip over symbol table entries
- buffer += sizeof(intptr_t);
- buffer += len;
-
- len = *(intptr_t*)buffer; // skip over shared dictionary entries
+ int len = *(intptr_t*)buffer; // skip over shared dictionary entries
buffer += sizeof(intptr_t);
buffer += len;
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -24,6 +24,7 @@
#ifndef SHARE_VM_MEMORY_METASPACE_SHARED_HPP
#define SHARE_VM_MEMORY_METASPACE_SHARED_HPP
+#include "classfile/compactHashtable.hpp"
#include "memory/allocation.hpp"
#include "memory/memRegion.hpp"
#include "runtime/virtualspace.hpp"
@@ -45,12 +46,21 @@
class FileMapInfo;
+class MetaspaceSharedStats VALUE_OBJ_CLASS_SPEC {
+public:
+ MetaspaceSharedStats() {
+ memset(this, 0, sizeof(*this));
+ }
+ CompactHashtableStats symbol;
+};
+
// Class Data Sharing Support
class MetaspaceShared : AllStatic {
// CDS support
static ReservedSpace* _shared_rs;
static int _max_alignment;
+ static MetaspaceSharedStats _stats;
static bool _link_classes_made_progress;
static bool _check_classes_made_progress;
static bool _has_error_classes;
@@ -123,6 +133,10 @@
char** mc_top, char* mc_end);
static void serialize(SerializeClosure* sc);
+ static MetaspaceSharedStats* stats() {
+ return &_stats;
+ }
+
// JVM/TI RedefineClasses() support:
// Remap the shared readonly space to shared readwrite, private if
// sharing is enabled. Simply returns true if sharing is not enabled
--- a/hotspot/src/share/vm/memory/universe.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/memory/universe.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -694,103 +694,6 @@
// NarrowOopHeapBaseMin + heap_size < 32Gb
// HeapBased - Use compressed oops with heap base + encoding.
-// 4Gb
-static const uint64_t UnscaledOopHeapMax = (uint64_t(max_juint) + 1);
-// 32Gb
-// OopEncodingHeapMax == UnscaledOopHeapMax << LogMinObjAlignmentInBytes;
-
-char* Universe::preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode) {
- assert(is_size_aligned((size_t)OopEncodingHeapMax, alignment), "Must be");
- assert(is_size_aligned((size_t)UnscaledOopHeapMax, alignment), "Must be");
- assert(is_size_aligned(heap_size, alignment), "Must be");
-
- uintx heap_base_min_address_aligned = align_size_up(HeapBaseMinAddress, alignment);
-
- size_t base = 0;
-#ifdef _LP64
- if (UseCompressedOops) {
- assert(mode == UnscaledNarrowOop ||
- mode == ZeroBasedNarrowOop ||
- mode == HeapBasedNarrowOop, "mode is invalid");
- const size_t total_size = heap_size + heap_base_min_address_aligned;
- // Return specified base for the first request.
- if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) {
- base = heap_base_min_address_aligned;
-
- // If the total size is small enough to allow UnscaledNarrowOop then
- // just use UnscaledNarrowOop.
- } else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop)) {
- if ((total_size <= UnscaledOopHeapMax) && (mode == UnscaledNarrowOop) &&
- (Universe::narrow_oop_shift() == 0)) {
- // Use 32-bits oops without encoding and
- // place heap's top on the 4Gb boundary
- base = (UnscaledOopHeapMax - heap_size);
- } else {
- // Can't reserve with NarrowOopShift == 0
- Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
-
- if (mode == UnscaledNarrowOop ||
- mode == ZeroBasedNarrowOop && total_size <= UnscaledOopHeapMax) {
-
- // Use zero based compressed oops with encoding and
- // place heap's top on the 32Gb boundary in case
- // total_size > 4Gb or failed to reserve below 4Gb.
- uint64_t heap_top = OopEncodingHeapMax;
-
- // For small heaps, save some space for compressed class pointer
- // space so it can be decoded with no base.
- if (UseCompressedClassPointers && !UseSharedSpaces &&
- OopEncodingHeapMax <= 32*G) {
-
- uint64_t class_space = align_size_up(CompressedClassSpaceSize, alignment);
- assert(is_size_aligned((size_t)OopEncodingHeapMax-class_space,
- alignment), "difference must be aligned too");
- uint64_t new_top = OopEncodingHeapMax-class_space;
-
- if (total_size <= new_top) {
- heap_top = new_top;
- }
- }
-
- // Align base to the adjusted top of the heap
- base = heap_top - heap_size;
- }
- }
- } else {
- // UnscaledNarrowOop encoding didn't work, and no base was found for ZeroBasedOops or
- // HeapBasedNarrowOop encoding was requested. So, can't reserve below 32Gb.
- Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
- }
-
- // Set narrow_oop_base and narrow_oop_use_implicit_null_checks
- // used in ReservedHeapSpace() constructors.
- // The final values will be set in initialize_heap() below.
- if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax)) {
- // Use zero based compressed oops
- Universe::set_narrow_oop_base(NULL);
- // Don't need guard page for implicit checks in indexed
- // addressing mode with zero based Compressed Oops.
- Universe::set_narrow_oop_use_implicit_null_checks(true);
- } else {
- // Set to a non-NULL value so the ReservedSpace ctor computes
- // the correct no-access prefix.
- // The final value will be set in initialize_heap() below.
- Universe::set_narrow_oop_base((address)UnscaledOopHeapMax);
-#if defined(_WIN64) || defined(AIX)
- if (UseLargePages) {
- // Cannot allocate guard pages for implicit checks in indexed
- // addressing mode when large pages are specified on windows.
- Universe::set_narrow_oop_use_implicit_null_checks(false);
- }
-#endif // _WIN64
- }
- }
-#endif
-
- assert(is_ptr_aligned((char*)base, alignment), "Must be");
- return (char*)base; // also return NULL (don't care) for 32-bit VM
-}
-
jint Universe::initialize_heap() {
if (UseParallelGC) {
@@ -844,30 +747,13 @@
// See needs_explicit_null_check.
// Only set the heap base for compressed oops because it indicates
// compressed oops for pstack code.
- if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax)) {
- // Can't reserve heap below 32Gb.
- // keep the Universe::narrow_oop_base() set in Universe::reserve_heap()
+ if ((uint64_t)Universe::heap()->reserved_region().end() > UnscaledOopHeapMax) {
+ // Didn't reserve heap below 4Gb. Must shift.
Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
-#ifdef AIX
- // There is no protected page before the heap. This assures all oops
- // are decoded so that NULL is preserved, so this page will not be accessed.
- Universe::set_narrow_oop_use_implicit_null_checks(false);
-#endif
- } else {
+ }
+ if ((uint64_t)Universe::heap()->reserved_region().end() <= OopEncodingHeapMax) {
+ // Did reserve heap below 32Gb. Can use base == 0;
Universe::set_narrow_oop_base(0);
-#ifdef _WIN64
- if (!Universe::narrow_oop_use_implicit_null_checks()) {
- // Don't need guard page for implicit checks in indexed addressing
- // mode with zero based Compressed Oops.
- Universe::set_narrow_oop_use_implicit_null_checks(true);
- }
-#endif // _WIN64
- if((uint64_t)Universe::heap()->reserved_region().end() > UnscaledOopHeapMax) {
- // Can't reserve heap below 4Gb.
- Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
- } else {
- Universe::set_narrow_oop_shift(0);
- }
}
Universe::set_narrow_ptrs_base(Universe::narrow_oop_base());
@@ -875,6 +761,11 @@
if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) {
Universe::print_compressed_oops_mode();
}
+
+ // Tell tests in which mode we run.
+ Arguments::PropertyList_add(new SystemProperty("java.vm.compressedOopsMode",
+ narrow_oop_mode_to_string(narrow_oop_mode()),
+ false));
}
// Universe::narrow_oop_base() is one page below the heap.
assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() -
@@ -903,22 +794,27 @@
tty->print(", Compressed Oops mode: %s", narrow_oop_mode_to_string(narrow_oop_mode()));
if (Universe::narrow_oop_base() != 0) {
- tty->print(":" PTR_FORMAT, Universe::narrow_oop_base());
+ tty->print(": " PTR_FORMAT, Universe::narrow_oop_base());
}
if (Universe::narrow_oop_shift() != 0) {
tty->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");
+ }
+
tty->cr();
tty->cr();
}
-// Reserve the Java heap, which is now the same for all GCs.
ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) {
+
assert(alignment <= Arguments::conservative_max_heap_alignment(),
err_msg("actual alignment "SIZE_FORMAT" must be within maximum heap alignment "SIZE_FORMAT,
alignment, Arguments::conservative_max_heap_alignment()));
+
size_t total_reserved = align_size_up(heap_size, alignment);
assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())),
"heap size is too big for compressed oops");
@@ -928,46 +824,31 @@
|| UseParallelGC
|| use_large_pages, "Wrong alignment to use large pages");
- char* addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::UnscaledNarrowOop);
-
- ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, addr);
+ // Now create the space.
+ ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages);
- if (UseCompressedOops) {
- if (addr != NULL && !total_rs.is_reserved()) {
- // Failed to reserve at specified address - the requested memory
- // region is taken already, for example, by 'java' launcher.
- // Try again to reserver heap higher.
- addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::ZeroBasedNarrowOop);
-
- ReservedHeapSpace total_rs0(total_reserved, alignment,
- use_large_pages, addr);
+ if (total_rs.is_reserved()) {
+ assert((total_reserved == total_rs.size()) && ((uintptr_t)total_rs.base() % alignment == 0),
+ "must be exactly of required size and alignment");
+ // We are good.
- if (addr != NULL && !total_rs0.is_reserved()) {
- // Failed to reserve at specified address again - give up.
- addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::HeapBasedNarrowOop);
- assert(addr == NULL, "");
+ if (UseCompressedOops) {
+ // Universe::initialize_heap() will reset this to NULL if unscaled
+ // or zero-based narrow oops are actually used.
+ // Else heap start and base MUST differ, so that NULL can be encoded nonambigous.
+ Universe::set_narrow_oop_base((address)total_rs.compressed_oop_base());
+ }
- ReservedHeapSpace total_rs1(total_reserved, alignment,
- use_large_pages, addr);
- total_rs = total_rs1;
- } else {
- total_rs = total_rs0;
- }
- }
- }
-
- if (!total_rs.is_reserved()) {
- vm_exit_during_initialization(err_msg("Could not reserve enough space for " SIZE_FORMAT "KB object heap", total_reserved/K));
return total_rs;
}
- if (UseCompressedOops) {
- // Universe::initialize_heap() will reset this to NULL if unscaled
- // or zero-based narrow oops are actually used.
- address base = (address)(total_rs.base() - os::vm_page_size());
- Universe::set_narrow_oop_base(base);
- }
- return total_rs;
+ vm_exit_during_initialization(
+ err_msg("Could not reserve enough space for " SIZE_FORMAT "KB object heap",
+ total_reserved/K));
+
+ // satisfy compiler
+ ShouldNotReachHere();
+ return ReservedHeapSpace(0, 0, false);
}
@@ -985,6 +866,8 @@
return "32-bit";
case ZeroBasedNarrowOop:
return "Zero based";
+ case DisjointBaseNarrowOop:
+ return "Non-zero disjoint base";
case HeapBasedNarrowOop:
return "Non-zero based";
}
@@ -995,6 +878,10 @@
Universe::NARROW_OOP_MODE Universe::narrow_oop_mode() {
+ if (narrow_oop_base_disjoint()) {
+ return DisjointBaseNarrowOop;
+ }
+
if (narrow_oop_base() != 0) {
return HeapBasedNarrowOop;
}
@@ -1176,9 +1063,7 @@
MemoryService::set_universe_heap(Universe::_collectedHeap);
#if INCLUDE_CDS
- if (UseSharedSpaces) {
- SharedClassUtil::initialize(CHECK_false);
- }
+ SharedClassUtil::initialize(CHECK_false);
#endif
return true;
}
@@ -1189,119 +1074,6 @@
}
-// %%% The Universe::flush_foo methods belong in CodeCache.
-
-// Flushes compiled methods dependent on dependee.
-void Universe::flush_dependents_on(instanceKlassHandle dependee) {
- assert_lock_strong(Compile_lock);
-
- if (CodeCache::number_of_nmethods_with_dependencies() == 0) return;
-
- // CodeCache can only be updated by a thread_in_VM and they will all be
- // stopped during the safepoint so CodeCache will be safe to update without
- // holding the CodeCache_lock.
-
- KlassDepChange changes(dependee);
-
- // Compute the dependent nmethods
- if (CodeCache::mark_for_deoptimization(changes) > 0) {
- // At least one nmethod has been marked for deoptimization
- VM_Deoptimize op;
- VMThread::execute(&op);
- }
-}
-
-// Flushes compiled methods dependent on a particular CallSite
-// instance when its target is different than the given MethodHandle.
-void Universe::flush_dependents_on(Handle call_site, Handle method_handle) {
- assert_lock_strong(Compile_lock);
-
- if (CodeCache::number_of_nmethods_with_dependencies() == 0) return;
-
- // CodeCache can only be updated by a thread_in_VM and they will all be
- // stopped during the safepoint so CodeCache will be safe to update without
- // holding the CodeCache_lock.
-
- CallSiteDepChange changes(call_site(), method_handle());
-
- // Compute the dependent nmethods that have a reference to a
- // CallSite object. We use InstanceKlass::mark_dependent_nmethod
- // directly instead of CodeCache::mark_for_deoptimization because we
- // want dependents on the call site class only not all classes in
- // the ContextStream.
- int marked = 0;
- {
- MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
- InstanceKlass* call_site_klass = InstanceKlass::cast(call_site->klass());
- marked = call_site_klass->mark_dependent_nmethods(changes);
- }
- if (marked > 0) {
- // At least one nmethod has been marked for deoptimization
- VM_Deoptimize op;
- VMThread::execute(&op);
- }
-}
-
-#ifdef HOTSWAP
-// Flushes compiled methods dependent on dependee in the evolutionary sense
-void Universe::flush_evol_dependents_on(instanceKlassHandle ev_k_h) {
- // --- Compile_lock is not held. However we are at a safepoint.
- assert_locked_or_safepoint(Compile_lock);
- if (CodeCache::number_of_nmethods_with_dependencies() == 0) return;
-
- // CodeCache can only be updated by a thread_in_VM and they will all be
- // stopped during the safepoint so CodeCache will be safe to update without
- // holding the CodeCache_lock.
-
- // Compute the dependent nmethods
- if (CodeCache::mark_for_evol_deoptimization(ev_k_h) > 0) {
- // At least one nmethod has been marked for deoptimization
-
- // All this already happens inside a VM_Operation, so we'll do all the work here.
- // Stuff copied from VM_Deoptimize and modified slightly.
-
- // We do not want any GCs to happen while we are in the middle of this VM operation
- ResourceMark rm;
- DeoptimizationMarker dm;
-
- // Deoptimize all activations depending on marked nmethods
- Deoptimization::deoptimize_dependents();
-
- // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
- CodeCache::make_marked_nmethods_not_entrant();
- }
-}
-#endif // HOTSWAP
-
-
-// Flushes compiled methods dependent on dependee
-void Universe::flush_dependents_on_method(methodHandle m_h) {
- // --- Compile_lock is not held. However we are at a safepoint.
- assert_locked_or_safepoint(Compile_lock);
-
- // CodeCache can only be updated by a thread_in_VM and they will all be
- // stopped dring the safepoint so CodeCache will be safe to update without
- // holding the CodeCache_lock.
-
- // Compute the dependent nmethods
- if (CodeCache::mark_for_deoptimization(m_h()) > 0) {
- // At least one nmethod has been marked for deoptimization
-
- // All this already happens inside a VM_Operation, so we'll do all the work here.
- // Stuff copied from VM_Deoptimize and modified slightly.
-
- // We do not want any GCs to happen while we are in the middle of this VM operation
- ResourceMark rm;
- DeoptimizationMarker dm;
-
- // Deoptimize all activations depending on marked nmethods
- Deoptimization::deoptimize_dependents();
-
- // Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
- CodeCache::make_marked_nmethods_not_entrant();
- }
-}
-
void Universe::print() {
print_on(gclog_or_tty);
}
--- a/hotspot/src/share/vm/memory/universe.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/memory/universe.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -102,8 +102,8 @@
friend class MarkSweep;
friend class oopDesc;
friend class ClassLoader;
- friend class Arguments;
friend class SystemDictionary;
+ friend class ReservedHeapSpace;
friend class VMStructs;
friend class VM_PopulateDumpSharedSpace;
friend class Metaspace;
@@ -351,17 +351,40 @@
// NarrowOopHeapBaseMin + heap_size < 4Gb
// 1 - Use zero based compressed oops with encoding when
// NarrowOopHeapBaseMin + heap_size < 32Gb
- // 2 - Use compressed oops with heap base + encoding.
+ // 2 - Use compressed oops with disjoint heap base if
+ // base is 32G-aligned and base > 0. This allows certain
+ // optimizations in encoding/decoding.
+ // Disjoint: Bits used in base are disjoint from bits used
+ // for oops ==> oop = (cOop << 3) | base. One can disjoint
+ // the bits of an oop into base and compressed oop.
+ // 3 - Use compressed oops with heap base + encoding.
enum NARROW_OOP_MODE {
UnscaledNarrowOop = 0,
ZeroBasedNarrowOop = 1,
- HeapBasedNarrowOop = 2
+ DisjointBaseNarrowOop = 2,
+ HeapBasedNarrowOop = 3,
+ AnyNarrowOopMode = 4
};
static NARROW_OOP_MODE narrow_oop_mode();
static const char* narrow_oop_mode_to_string(NARROW_OOP_MODE mode);
static char* preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode);
static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode);
- static address narrow_oop_base() { return _narrow_oop._base; }
+ static address narrow_oop_base() { return _narrow_oop._base; }
+ // Test whether bits of addr and possible offsets into the heap overlap.
+ static bool is_disjoint_heap_base_address(address addr) {
+ return (((uint64_t)(intptr_t)addr) &
+ (((uint64_t)UCONST64(0xFFFFffffFFFFffff)) >> (32-LogMinObjAlignmentInBytes))) == 0;
+ }
+ // Check for disjoint base compressed oops.
+ static bool narrow_oop_base_disjoint() {
+ return _narrow_oop._base != NULL && is_disjoint_heap_base_address(_narrow_oop._base);
+ }
+ // Check for real heapbased compressed oops.
+ // We must subtract the base as the bits overlap.
+ // If we negate above function, we also get unscaled and zerobased.
+ static bool narrow_oop_base_overlaps() {
+ return _narrow_oop._base != NULL && !is_disjoint_heap_base_address(_narrow_oop._base);
+ }
static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); }
static int narrow_oop_shift() { return _narrow_oop._shift; }
static bool narrow_oop_use_implicit_null_checks() { return _narrow_oop._use_implicit_null_checks; }
@@ -461,16 +484,6 @@
static uintptr_t verify_mark_bits() PRODUCT_RETURN0;
static uintptr_t verify_mark_mask() PRODUCT_RETURN0;
- // Flushing and deoptimization
- static void flush_dependents_on(instanceKlassHandle dependee);
- static void flush_dependents_on(Handle call_site, Handle method_handle);
-#ifdef HOTSWAP
- // Flushing and deoptimization in case of evolution
- static void flush_evol_dependents_on(instanceKlassHandle dependee);
-#endif // HOTSWAP
- // Support for fullspeed debugging
- static void flush_dependents_on_method(methodHandle dependee);
-
// Compiler support
static int base_vtable_size() { return _base_vtable_size; }
};
--- a/hotspot/src/share/vm/oops/fieldStreams.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/oops/fieldStreams.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -51,7 +51,7 @@
int init_generic_signature_start_slot() {
int length = _fields->length();
- int num_fields = 0;
+ int num_fields = _index;
int skipped_generic_signature_slots = 0;
FieldInfo* fi;
AccessFlags flags;
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -3543,11 +3543,12 @@
("purge: %s(%s): prev method @%d in version @%d is alive",
method->name()->as_C_string(),
method->signature()->as_C_string(), j, version));
+#ifdef ASSERT
if (method->method_data() != NULL) {
- // Clean out any weak method links for running methods
- // (also should include not EMCP methods)
- method->method_data()->clean_weak_method_links();
+ // Verify MethodData for running methods don't refer to old methods.
+ method->method_data()->verify_clean_weak_method_links();
}
+#endif // ASSERT
}
}
}
@@ -3561,15 +3562,17 @@
deleted_count));
}
- // Clean MethodData of this class's methods so they don't refer to
+#ifdef ASSERT
+ // Verify clean MethodData for this class's methods, e.g. they don't refer to
// old methods that are no longer running.
Array<Method*>* methods = ik->methods();
int num_methods = methods->length();
- for (int index2 = 0; index2 < num_methods; ++index2) {
- if (methods->at(index2)->method_data() != NULL) {
- methods->at(index2)->method_data()->clean_weak_method_links();
+ for (int index = 0; index < num_methods; ++index) {
+ if (methods->at(index)->method_data() != NULL) {
+ methods->at(index)->method_data()->verify_clean_weak_method_links();
}
}
+#endif // ASSERT
}
void InstanceKlass::mark_newly_obsolete_methods(Array<Method*>* old_methods,
--- a/hotspot/src/share/vm/oops/klassVtable.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -100,17 +100,21 @@
vtable_length = Universe::base_vtable_size();
}
- if (super == NULL && !Universe::is_bootstrapping() &&
- vtable_length != Universe::base_vtable_size()) {
- // Someone is attempting to redefine java.lang.Object incorrectly. The
- // only way this should happen is from
- // SystemDictionary::resolve_from_stream(), which will detect this later
- // and throw a security exception. So don't assert here to let
- // the exception occur.
- vtable_length = Universe::base_vtable_size();
+ if (super == NULL && vtable_length != Universe::base_vtable_size()) {
+ if (Universe::is_bootstrapping()) {
+ // Someone is attempting to override java.lang.Object incorrectly on the
+ // bootclasspath. The JVM cannot recover from this error including throwing
+ // an exception
+ vm_exit_during_initialization("Incompatible definition of java.lang.Object");
+ } else {
+ // Someone is attempting to redefine java.lang.Object incorrectly. The
+ // only way this should happen is from
+ // SystemDictionary::resolve_from_stream(), which will detect this later
+ // and throw a security exception. So don't assert here to let
+ // the exception occur.
+ vtable_length = Universe::base_vtable_size();
+ }
}
- assert(super != NULL || vtable_length == Universe::base_vtable_size(),
- "bad vtable size for class Object");
assert(vtable_length % vtableEntry::size() == 0, "bad vtable length");
assert(vtable_length >= Universe::base_vtable_size(), "vtable too small");
--- a/hotspot/src/share/vm/oops/method.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/oops/method.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/systemDictionary.hpp"
+#include "code/codeCache.hpp"
#include "code/debugInfoRec.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/bytecodeStream.hpp"
@@ -1727,7 +1728,7 @@
// Deoptimize all dependents on this method
HandleMark hm(thread);
methodHandle mh(thread, method);
- Universe::flush_dependents_on_method(mh);
+ CodeCache::flush_dependents_on_method(mh);
}
}
--- a/hotspot/src/share/vm/oops/methodData.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/oops/methodData.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -1283,6 +1283,11 @@
DataLayout::compute_size_in_bytes(SpeculativeTrapData::static_cell_count()),
"code needs to be adjusted");
+ // Do not create one of these if method has been redefined.
+ if (m != NULL && m->is_old()) {
+ return NULL;
+ }
+
DataLayout* dp = extra_data_base();
DataLayout* end = args_data_limit();
@@ -1554,9 +1559,7 @@
class CleanExtraDataMethodClosure : public CleanExtraDataClosure {
public:
CleanExtraDataMethodClosure() {}
- bool is_live(Method* m) {
- return !m->is_old() || m->on_stack();
- }
+ bool is_live(Method* m) { return !m->is_old(); }
};
@@ -1658,3 +1661,16 @@
clean_extra_data(&cl);
verify_extra_data_clean(&cl);
}
+
+#ifdef ASSERT
+void MethodData::verify_clean_weak_method_links() {
+ for (ProfileData* data = first_data();
+ is_valid(data);
+ data = next_data(data)) {
+ data->verify_clean_weak_method_links();
+ }
+
+ CleanExtraDataMethodClosure cl;
+ verify_extra_data_clean(&cl);
+}
+#endif // ASSERT
--- a/hotspot/src/share/vm/oops/methodData.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/oops/methodData.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -254,6 +254,7 @@
// Redefinition support
void clean_weak_method_links();
+ DEBUG_ONLY(void verify_clean_weak_method_links();)
};
@@ -511,6 +512,7 @@
// Redefinition support
virtual void clean_weak_method_links() {}
+ DEBUG_ONLY(virtual void verify_clean_weak_method_links() {})
// CI translation: ProfileData can represent both MethodDataOop data
// as well as CIMethodData data. This function is provided for translating
@@ -1971,6 +1973,7 @@
}
void set_method(Method* m) {
+ assert(!m->is_old(), "cannot add old methods");
set_intptr_at(speculative_trap_method, (intptr_t)m);
}
@@ -2480,6 +2483,7 @@
void clean_method_data(BoolObjectClosure* is_alive);
void clean_weak_method_links();
+ DEBUG_ONLY(void verify_clean_weak_method_links();)
Mutex* extra_data_lock() { return &_extra_data_lock; }
};
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -669,6 +669,13 @@
product_pd(bool, TrapBasedRangeChecks, \
"Generate code for range checks that uses a cmp and trap " \
"instruction raising SIGTRAP. Used on PPC64.") \
+ \
+ product(intx, ArrayCopyLoadStoreMaxElem, 8, \
+ "Maximum number of arraycopy elements inlined as a sequence of" \
+ "loads/stores") \
+ \
+ 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)
--- a/hotspot/src/share/vm/opto/c2compiler.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/opto/c2compiler.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -39,6 +39,9 @@
const char* C2Compiler::retry_no_escape_analysis() {
return "retry without escape analysis";
}
+const char* C2Compiler::retry_class_loading_during_parsing() {
+ return "retry class loading during parsing";
+}
bool C2Compiler::init_c2_runtime() {
// Check assumptions used while running ADLC
@@ -104,6 +107,10 @@
// Check result and retry if appropriate.
if (C.failure_reason() != NULL) {
+ if (C.failure_reason_is(retry_class_loading_during_parsing())) {
+ env->report_failure(C.failure_reason());
+ continue; // retry
+ }
if (C.failure_reason_is(retry_no_subsuming_loads())) {
assert(subsume_loads, "must make progress");
subsume_loads = false;
--- a/hotspot/src/share/vm/opto/c2compiler.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/opto/c2compiler.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -47,6 +47,7 @@
// sentinel value used to trigger backtracking in compile_method().
static const char* retry_no_subsuming_loads();
static const char* retry_no_escape_analysis();
+ static const char* retry_class_loading_during_parsing();
// Print compilation timers and statistics
void print_timers();
--- a/hotspot/src/share/vm/opto/callnode.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/opto/callnode.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -28,6 +28,7 @@
#include "opto/callGenerator.hpp"
#include "opto/callnode.hpp"
#include "opto/castnode.hpp"
+#include "opto/convertnode.hpp"
#include "opto/escape.hpp"
#include "opto/locknode.hpp"
#include "opto/machnode.hpp"
@@ -1818,7 +1819,10 @@
}
ArrayCopyNode::ArrayCopyNode(Compile* C, bool alloc_tightly_coupled)
- : CallNode(arraycopy_type(), NULL, TypeRawPtr::BOTTOM), _alloc_tightly_coupled(alloc_tightly_coupled), _kind(ArrayCopy) {
+ : CallNode(arraycopy_type(), NULL, TypeRawPtr::BOTTOM),
+ _alloc_tightly_coupled(alloc_tightly_coupled),
+ _kind(None),
+ _arguments_validated(false) {
init_class_id(Class_ArrayCopy);
init_flags(Flag_is_macro);
C->add_macro_node(this);
@@ -1870,3 +1874,136 @@
st->print(" (%s%s)", _kind_names[_kind], _alloc_tightly_coupled ? ", tightly coupled allocation" : "");
}
#endif
+
+int ArrayCopyNode::get_count(PhaseGVN *phase) const {
+ Node* src = in(ArrayCopyNode::Src);
+ const Type* src_type = phase->type(src);
+
+ assert(is_clonebasic(), "unexpected arraycopy type");
+ if (src_type->isa_instptr()) {
+ const TypeInstPtr* inst_src = src_type->is_instptr();
+ ciInstanceKlass* ik = inst_src->klass()->as_instance_klass();
+ // ciInstanceKlass::nof_nonstatic_fields() doesn't take injected
+ // fields into account. They are rare anyway so easier to simply
+ // skip instances with injected fields.
+ if ((!inst_src->klass_is_exact() && (ik->is_interface() || ik->has_subklass())) || ik->has_injected_fields()) {
+ return -1;
+ }
+ int nb_fields = ik->nof_nonstatic_fields();
+ return nb_fields;
+ }
+ return -1;
+}
+
+Node* ArrayCopyNode::try_clone_instance(PhaseGVN *phase, bool can_reshape, int count) {
+ assert(is_clonebasic(), "unexpected arraycopy type");
+
+ Node* src = in(ArrayCopyNode::Src);
+ Node* dest = in(ArrayCopyNode::Dest);
+ Node* ctl = in(TypeFunc::Control);
+ Node* in_mem = in(TypeFunc::Memory);
+
+ const Type* src_type = phase->type(src);
+ const Type* dest_type = phase->type(dest);
+
+ assert(src->is_AddP(), "should be base + off");
+ assert(dest->is_AddP(), "should be base + off");
+ Node* base_src = src->in(AddPNode::Base);
+ Node* base_dest = dest->in(AddPNode::Base);
+
+ MergeMemNode* mem = MergeMemNode::make(in_mem);
+
+ const TypeInstPtr* inst_src = src_type->is_instptr();
+
+ if (!inst_src->klass_is_exact()) {
+ ciInstanceKlass* ik = inst_src->klass()->as_instance_klass();
+ assert(!ik->is_interface() && !ik->has_subklass(), "inconsistent klass hierarchy");
+ phase->C->dependencies()->assert_leaf_type(ik);
+ }
+
+ ciInstanceKlass* ik = inst_src->klass()->as_instance_klass();
+ assert(ik->nof_nonstatic_fields() <= ArrayCopyLoadStoreMaxElem, "too many fields");
+
+ for (int i = 0; i < count; i++) {
+ ciField* field = ik->nonstatic_field_at(i);
+ int fieldidx = phase->C->alias_type(field)->index();
+ const TypePtr* adr_type = phase->C->alias_type(field)->adr_type();
+ Node* off = phase->MakeConX(field->offset());
+ Node* next_src = phase->transform(new AddPNode(base_src,base_src,off));
+ Node* next_dest = phase->transform(new AddPNode(base_dest,base_dest,off));
+ BasicType bt = field->layout_type();
+
+ const Type *type;
+ if (bt == T_OBJECT) {
+ if (!field->type()->is_loaded()) {
+ type = TypeInstPtr::BOTTOM;
+ } else {
+ ciType* field_klass = field->type();
+ type = TypeOopPtr::make_from_klass(field_klass->as_klass());
+ }
+ } else {
+ type = Type::get_const_basic_type(bt);
+ }
+
+ Node* v = LoadNode::make(*phase, ctl, mem->memory_at(fieldidx), next_src, adr_type, type, bt, MemNode::unordered);
+ v = phase->transform(v);
+ Node* s = StoreNode::make(*phase, ctl, mem->memory_at(fieldidx), next_dest, adr_type, v, bt, MemNode::unordered);
+ s = phase->transform(s);
+ mem->set_memory_at(fieldidx, s);
+ }
+
+ if (!finish_transform(phase, can_reshape, ctl, mem)) {
+ return NULL;
+ }
+
+ return mem;
+}
+
+bool ArrayCopyNode::finish_transform(PhaseGVN *phase, bool can_reshape,
+ Node* ctl, Node *mem) {
+ if (can_reshape) {
+ PhaseIterGVN* igvn = phase->is_IterGVN();
+ assert(is_clonebasic(), "unexpected arraycopy type");
+ Node* out_mem = proj_out(TypeFunc::Memory);
+
+ if (out_mem->outcnt() != 1 || !out_mem->raw_out(0)->is_MergeMem() ||
+ out_mem->raw_out(0)->outcnt() != 1 || !out_mem->raw_out(0)->raw_out(0)->is_MemBar()) {
+ assert(!GraphKit::use_ReduceInitialCardMarks(), "can only happen with card marking");
+ return false;
+ }
+
+ igvn->replace_node(out_mem->raw_out(0), mem);
+
+ Node* out_ctl = proj_out(TypeFunc::Control);
+ igvn->replace_node(out_ctl, ctl);
+ }
+ return true;
+}
+
+
+Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+
+ if (StressArrayCopyMacroNode && !can_reshape) return NULL;
+
+ // See if it's a small array copy and we can inline it as
+ // loads/stores
+ // Here we can only do:
+ // - clone for which we don't need to do card marking
+
+ if (!is_clonebasic()) {
+ return NULL;
+ }
+
+ if (in(TypeFunc::Control)->is_top() || in(TypeFunc::Memory)->is_top()) {
+ return NULL;
+ }
+
+ int count = get_count(phase);
+
+ if (count < 0 || count > ArrayCopyLoadStoreMaxElem) {
+ return NULL;
+ }
+
+ Node* mem = try_clone_instance(phase, can_reshape, count);
+ return mem;
+}
--- a/hotspot/src/share/vm/opto/callnode.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/opto/callnode.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -1070,8 +1070,8 @@
// What kind of arraycopy variant is this?
enum {
+ None, // not set yet
ArrayCopy, // System.arraycopy()
- ArrayCopyNoTest, // System.arraycopy(), all arguments validated
CloneBasic, // A clone that can be copied by 64 bit chunks
CloneOop, // An oop array clone
CopyOf, // Arrays.copyOf()
@@ -1095,6 +1095,8 @@
// LibraryCallKit::tightly_coupled_allocation() is called.
bool _alloc_tightly_coupled;
+ bool _arguments_validated;
+
static const TypeFunc* arraycopy_type() {
const Type** fields = TypeTuple::fields(ParmLimit - TypeFunc::Parms);
fields[Src] = TypeInstPtr::BOTTOM;
@@ -1118,6 +1120,13 @@
ArrayCopyNode(Compile* C, bool alloc_tightly_coupled);
+ int get_count(PhaseGVN *phase) const;
+ static const TypePtr* get_address_type(PhaseGVN *phase, Node* n);
+
+ Node* try_clone_instance(PhaseGVN *phase, bool can_reshape, int count);
+ bool finish_transform(PhaseGVN *phase, bool can_reshape,
+ Node* ctl, Node *mem);
+
public:
enum {
@@ -1143,23 +1152,23 @@
void connect_outputs(GraphKit* kit);
- bool is_arraycopy() const { return _kind == ArrayCopy; }
- bool is_arraycopy_notest() const { return _kind == ArrayCopyNoTest; }
- bool is_clonebasic() const { return _kind == CloneBasic; }
- bool is_cloneoop() const { return _kind == CloneOop; }
- bool is_copyof() const { return _kind == CopyOf; }
- bool is_copyofrange() const { return _kind == CopyOfRange; }
+ bool is_arraycopy() const { assert(_kind != None, "should bet set"); return _kind == ArrayCopy; }
+ bool is_arraycopy_validated() const { assert(_kind != None, "should bet set"); return _kind == ArrayCopy && _arguments_validated; }
+ bool is_clonebasic() const { assert(_kind != None, "should bet set"); return _kind == CloneBasic; }
+ bool is_cloneoop() const { assert(_kind != None, "should bet set"); return _kind == CloneOop; }
+ bool is_copyof() const { assert(_kind != None, "should bet set"); return _kind == CopyOf; }
+ bool is_copyofrange() const { assert(_kind != None, "should bet set"); return _kind == CopyOfRange; }
- void set_arraycopy() { _kind = ArrayCopy; }
- void set_arraycopy_notest() { _kind = ArrayCopyNoTest; }
- void set_clonebasic() { _kind = CloneBasic; }
- void set_cloneoop() { _kind = CloneOop; }
- void set_copyof() { _kind = CopyOf; }
- void set_copyofrange() { _kind = CopyOfRange; }
+ void set_arraycopy(bool validated) { assert(_kind == None, "shouldn't bet set yet"); _kind = ArrayCopy; _arguments_validated = validated; }
+ void set_clonebasic() { assert(_kind == None, "shouldn't bet set yet"); _kind = CloneBasic; }
+ void set_cloneoop() { assert(_kind == None, "shouldn't bet set yet"); _kind = CloneOop; }
+ void set_copyof() { assert(_kind == None, "shouldn't bet set yet"); _kind = CopyOf; _arguments_validated = false; }
+ void set_copyofrange() { assert(_kind == None, "shouldn't bet set yet"); _kind = CopyOfRange; _arguments_validated = false; }
virtual int Opcode() const;
virtual uint size_of() const; // Size is bigger
virtual bool guaranteed_safepoint() { return false; }
+ virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
bool is_alloc_tightly_coupled() const { return _alloc_tightly_coupled; }
--- a/hotspot/src/share/vm/opto/compile.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/opto/compile.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -774,7 +774,9 @@
}
JVMState* jvms = build_start_state(start(), tf());
if ((jvms = cg->generate(jvms)) == NULL) {
- record_method_not_compilable("method parse failed");
+ if (!failure_reason_is(C2Compiler::retry_class_loading_during_parsing())) {
+ record_method_not_compilable("method parse failed");
+ }
return;
}
GraphKit kit(jvms);
--- a/hotspot/src/share/vm/opto/library_call.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/opto/library_call.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -4475,8 +4475,11 @@
ArrayCopyNode* ac = ArrayCopyNode::make(this, false, src, NULL, dest, NULL, countx, false);
ac->set_clonebasic();
Node* n = _gvn.transform(ac);
- assert(n == ac, "cannot disappear");
- set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), raw_adr_type);
+ if (n == ac) {
+ set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), raw_adr_type);
+ } else {
+ set_all_memory(n);
+ }
// If necessary, emit some card marks afterwards. (Non-arrays only.)
if (card_mark) {
@@ -4541,6 +4544,26 @@
Node* obj = null_check_receiver();
if (stopped()) return true;
+ const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
+
+ // If we are going to clone an instance, we need its exact type to
+ // know the number and types of fields to convert the clone to
+ // loads/stores. Maybe a speculative type can help us.
+ if (!obj_type->klass_is_exact() &&
+ obj_type->speculative_type() != NULL &&
+ obj_type->speculative_type()->is_instance_klass()) {
+ ciInstanceKlass* spec_ik = obj_type->speculative_type()->as_instance_klass();
+ if (spec_ik->nof_nonstatic_fields() <= ArrayCopyLoadStoreMaxElem &&
+ !spec_ik->has_injected_fields()) {
+ ciKlass* k = obj_type->klass();
+ if (!k->is_instance_klass() ||
+ k->as_instance_klass()->is_interface() ||
+ k->as_instance_klass()->has_subklass()) {
+ obj = maybe_cast_profiled_obj(obj, obj_type->speculative_type(), false);
+ }
+ }
+ }
+
Node* obj_klass = load_object_klass(obj);
const TypeKlassPtr* tklass = _gvn.type(obj_klass)->isa_klassptr();
const TypeOopPtr* toop = ((tklass != NULL)
@@ -4743,7 +4766,7 @@
sfpt->set_memory(map()->memory());
}
- bool notest = false;
+ bool validated = false;
const Type* src_type = _gvn.type(src);
const Type* dest_type = _gvn.type(dest);
@@ -4847,7 +4870,7 @@
if (!too_many_traps(Deoptimization::Reason_intrinsic) && !src->is_top() && !dest->is_top()) {
// validate arguments: enables transformation the ArrayCopyNode
- notest = true;
+ validated = true;
RegionNode* slow_region = new RegionNode(1);
record_for_igvn(slow_region);
@@ -4922,13 +4945,15 @@
load_object_klass(src), load_object_klass(dest),
load_array_length(src), load_array_length(dest));
- if (notest) {
- ac->set_arraycopy_notest();
- }
+ ac->set_arraycopy(validated);
Node* n = _gvn.transform(ac);
- assert(n == ac, "cannot disappear");
- ac->connect_outputs(this);
+ if (n == ac) {
+ ac->connect_outputs(this);
+ } else {
+ assert(validated, "shouldn't transform if all arguments not validated");
+ set_all_memory(n);
+ }
return true;
}
--- a/hotspot/src/share/vm/opto/macroArrayCopy.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/opto/macroArrayCopy.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -519,7 +519,8 @@
// Test S[] against D[], not S against D, because (probably)
// the secondary supertype cache is less busy for S[] than S.
// This usually only matters when D is an interface.
- Node* not_subtype_ctrl = ac->is_arraycopy_notest() ? top() : Phase::gen_subtype_check(src_klass, dest_klass, ctrl, mem, &_igvn);
+ Node* not_subtype_ctrl = ac->is_arraycopy_validated() ? top() :
+ Phase::gen_subtype_check(src_klass, dest_klass, ctrl, mem, &_igvn);
// Plug failing path into checked_oop_disjoint_arraycopy
if (not_subtype_ctrl != top()) {
Node* local_ctrl = not_subtype_ctrl;
@@ -1109,7 +1110,7 @@
assert(alloc != NULL, "expect alloc");
}
- assert(ac->is_arraycopy() || ac->is_arraycopy_notest(), "should be an arraycopy");
+ assert(ac->is_arraycopy() || ac->is_arraycopy_validated(), "should be an arraycopy");
// Compile time checks. If any of these checks cannot be verified at compile time,
// we do not make a fast path for this call. Instead, we let the call remain as it
@@ -1191,7 +1192,7 @@
RegionNode* slow_region = new RegionNode(1);
transform_later(slow_region);
- if (!ac->is_arraycopy_notest()) {
+ if (!ac->is_arraycopy_validated()) {
// (3) operands must not be null
// We currently perform our null checks with the null_check routine.
// This means that the null exceptions will be reported in the caller
--- a/hotspot/src/share/vm/opto/matcher.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/opto/matcher.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -433,6 +433,13 @@
// NullCheck oop_reg
//
inline static bool gen_narrow_oop_implicit_null_checks() {
+ // Advice matcher to perform null checks on the narrow oop side.
+ // Implicit checks are not possible on the uncompressed oop side anyway
+ // (at least not for read accesses).
+ // Performs significantly better (especially on Power 6).
+ if (!os::zero_page_read_protected()) {
+ return true;
+ }
return Universe::narrow_oop_use_implicit_null_checks() &&
(narrow_oop_use_complex_address() ||
Universe::narrow_oop_base() != NULL);
--- a/hotspot/src/share/vm/opto/parse1.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/opto/parse1.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -27,6 +27,7 @@
#include "interpreter/linkResolver.hpp"
#include "oops/method.hpp"
#include "opto/addnode.hpp"
+#include "opto/c2compiler.hpp"
#include "opto/castnode.hpp"
#include "opto/idealGraphPrinter.hpp"
#include "opto/locknode.hpp"
@@ -986,7 +987,18 @@
if (tf()->range()->cnt() > TypeFunc::Parms) {
const Type* ret_type = tf()->range()->field_at(TypeFunc::Parms);
Node* ret_phi = _gvn.transform( _exits.argument(0) );
- assert(_exits.control()->is_top() || !_gvn.type(ret_phi)->empty(), "return value must be well defined");
+ if (!_exits.control()->is_top() && _gvn.type(ret_phi)->empty()) {
+ // In case of concurrent class loading, the type we set for the
+ // ret_phi in build_exits() may have been too optimistic and the
+ // ret_phi may be top now.
+#ifdef ASSERT
+ {
+ MutexLockerEx ml(Compile_lock, Mutex::_no_safepoint_check_flag);
+ assert(ret_type->isa_ptr() && C->env()->system_dictionary_modification_counter_changed(), "return value must be well defined");
+ }
+#endif
+ C->record_failure(C2Compiler::retry_class_loading_during_parsing());
+ }
_exits.push_node(ret_type->basic_type(), ret_phi);
}
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -148,6 +148,10 @@
_scratch_classes[i] = NULL;
}
+ // Clean out MethodData pointing to old Method*
+ MethodDataCleaner clean_weak_method_links;
+ ClassLoaderDataGraph::classes_do(&clean_weak_method_links);
+
// Disable any dependent concurrent compilations
SystemDictionary::notice_modification();
@@ -155,8 +159,8 @@
// See jvmtiExport.hpp for detailed explanation.
JvmtiExport::set_has_redefined_a_class();
-// check_class() is optionally called for product bits, but is
-// always called for non-product bits.
+ // check_class() is optionally called for product bits, but is
+ // always called for non-product bits.
#ifdef PRODUCT
if (RC_TRACE_ENABLED(0x00004000)) {
#endif
@@ -3445,6 +3449,22 @@
}
}
+// Clean method data for this class
+void VM_RedefineClasses::MethodDataCleaner::do_klass(Klass* k) {
+ if (k->oop_is_instance()) {
+ InstanceKlass *ik = InstanceKlass::cast(k);
+ // Clean MethodData of this class's methods so they don't refer to
+ // old methods that are no longer running.
+ Array<Method*>* methods = ik->methods();
+ int num_methods = methods->length();
+ for (int index = 0; index < num_methods; ++index) {
+ if (methods->at(index)->method_data() != NULL) {
+ methods->at(index)->method_data()->clean_weak_method_links();
+ }
+ }
+ }
+}
+
void VM_RedefineClasses::update_jmethod_ids() {
for (int j = 0; j < _matching_methods_length; ++j) {
Method* old_method = _matching_old_methods[j];
@@ -3746,7 +3766,7 @@
// All dependencies have been recorded from startup or this is a second or
// subsequent use of RedefineClasses
if (JvmtiExport::all_dependencies_are_recorded()) {
- Universe::flush_evol_dependents_on(k_h);
+ CodeCache::flush_evol_dependents_on(k_h);
} else {
CodeCache::mark_all_nmethods_for_deoptimization();
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -511,6 +511,12 @@
void do_klass(Klass* k);
};
+ // Clean MethodData out
+ class MethodDataCleaner : public KlassClosure {
+ public:
+ MethodDataCleaner() {}
+ void do_klass(Klass* k);
+ };
public:
VM_RedefineClasses(jint class_count,
const jvmtiClassDefinition *class_defs,
--- a/hotspot/src/share/vm/prims/methodHandles.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/stringTable.hpp"
+#include "code/codeCache.hpp"
#include "compiler/compileBroker.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/oopMapCache.hpp"
@@ -1245,7 +1246,7 @@
{
// Walk all nmethods depending on this call site.
MutexLocker mu(Compile_lock, thread);
- Universe::flush_dependents_on(call_site, target);
+ CodeCache::flush_dependents_on(call_site, target);
java_lang_invoke_CallSite::set_target(call_site(), target());
}
}
@@ -1257,7 +1258,7 @@
{
// Walk all nmethods depending on this call site.
MutexLocker mu(Compile_lock, thread);
- Universe::flush_dependents_on(call_site, target);
+ CodeCache::flush_dependents_on(call_site, target);
java_lang_invoke_CallSite::set_target_volatile(call_site(), target());
}
}
--- a/hotspot/src/share/vm/prims/whitebox.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -1,5 +1,5 @@
/*
- * 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
@@ -176,11 +176,11 @@
WB_ENTRY(void, WB_ReadFromNoaccessArea(JNIEnv* env, jobject o))
size_t granularity = os::vm_allocation_granularity();
- ReservedHeapSpace rhs(100 * granularity, granularity, false, NULL);
+ ReservedHeapSpace rhs(100 * granularity, granularity, false);
VirtualSpace vs;
vs.initialize(rhs, 50 * granularity);
- //Check if constraints are complied
+ // Check if constraints are complied
if (!( UseCompressedOops && rhs.base() != NULL &&
Universe::narrow_oop_base() != NULL &&
Universe::narrow_oop_use_implicit_null_checks() )) {
@@ -203,7 +203,7 @@
static jint wb_stress_virtual_space_resize(size_t reserved_space_size,
size_t magnitude, size_t iterations) {
size_t granularity = os::vm_allocation_granularity();
- ReservedHeapSpace rhs(reserved_space_size * granularity, granularity, false, NULL);
+ ReservedHeapSpace rhs(reserved_space_size * granularity, granularity, false);
VirtualSpace vs;
if (!vs.initialize(rhs, 0)) {
tty->print_cr("Failed to initialize VirtualSpace. Can't proceed.");
@@ -1123,6 +1123,16 @@
attemptedNoSafepointValue == JNI_TRUE);
WB_END
+WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj))
+ oop obj_oop = JNIHandles::resolve(obj);
+ return (jboolean) obj_oop->mark()->has_monitor();
+WB_END
+
+WB_ENTRY(void, WB_ForceSafepoint(JNIEnv* env, jobject wb))
+ VM_ForceSafepoint force_safepoint_op;
+ VMThread::execute(&force_safepoint_op);
+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) {
@@ -1321,6 +1331,8 @@
{CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize },
{CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize },
{CC"assertMatchingSafepointCalls", CC"(ZZ)V", (void*)&WB_AssertMatchingSafepointCalls },
+ {CC"isMonitorInflated", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated },
+ {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint },
};
#undef CC
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -1522,15 +1522,6 @@
FLAG_SET_ERGO(bool, UseCompressedOops, true);
}
#endif
-#ifdef _WIN64
- if (UseLargePages && UseCompressedOops) {
- // Cannot allocate guard pages for implicit checks in indexed addressing
- // mode, when large pages are specified on windows.
- // This flag could be switched ON if narrow oop base address is set to 0,
- // see code in Universe::initialize_heap().
- Universe::set_narrow_oop_use_implicit_null_checks(false);
- }
-#endif // _WIN64
} else {
if (UseCompressedOops && !FLAG_IS_DEFAULT(UseCompressedOops)) {
warning("Max heap size too large for Compressed Oops");
@@ -2416,6 +2407,7 @@
#ifdef COMPILER1
status = status && verify_min_value(ValueMapInitialSize, 1, "ValueMapInitialSize");
#endif
+ status = status && verify_min_value(HeapSearchSteps, 1, "HeapSearchSteps");
if (PrintNMTStatistics) {
#if INCLUDE_NMT
@@ -4102,6 +4094,10 @@
PropertyList_add(plist, new_p);
}
+void Arguments::PropertyList_add(SystemProperty *element) {
+ PropertyList_add(&_system_properties, element);
+}
+
// This add maintains unique property key in the list.
void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, char* v, jboolean append) {
if (plist == NULL)
--- a/hotspot/src/share/vm/runtime/arguments.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -572,6 +572,7 @@
static void init_version_specific_system_properties();
// Property List manipulation
+ static void PropertyList_add(SystemProperty *element);
static void PropertyList_add(SystemProperty** plist, SystemProperty *element);
static void PropertyList_add(SystemProperty** plist, const char* k, char* v);
static void PropertyList_unique_add(SystemProperty** plist, const char* k, char* v) {
--- a/hotspot/src/share/vm/runtime/globals.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/runtime/globals.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -531,6 +531,11 @@
product_pd(uintx, HeapBaseMinAddress, \
"OS specific low limit for heap base address") \
\
+ product(uintx, HeapSearchSteps, 3 PPC64_ONLY(+17), \
+ "Heap allocation steps through preferred address regions to find" \
+ " where it can allocate the heap. Number of steps to take per " \
+ "region.") \
+ \
diagnostic(bool, PrintCompressedOopsMode, false, \
"Print compressed oops base address and encoding mode") \
\
@@ -3779,6 +3784,9 @@
NOT_LP64(LINUX_ONLY(2*G) NOT_LINUX(0)), \
"Address to allocate shared memory region for class data") \
\
+ product(uintx, SharedSymbolTableBucketSize, 4, \
+ "Average number of symbols per bucket in shared table") \
+ \
diagnostic(bool, IgnoreUnverifiableClassesDuringDump, false, \
"Do not quit -Xshare:dump even if we encounter unverifiable " \
"classes. Just exclude them from the shared dictionary.") \
--- a/hotspot/src/share/vm/runtime/virtualspace.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/runtime/virtualspace.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -43,21 +43,19 @@
// Don't force the alignment to be large page aligned,
// since that will waste memory.
size_t alignment = os::vm_allocation_granularity();
- initialize(size, alignment, large_pages, NULL, 0, false);
+ initialize(size, alignment, large_pages, NULL, false);
}
ReservedSpace::ReservedSpace(size_t size, size_t alignment,
bool large,
- char* requested_address,
- const size_t noaccess_prefix) {
- initialize(size+noaccess_prefix, alignment, large, requested_address,
- noaccess_prefix, false);
+ char* requested_address) {
+ initialize(size, alignment, large, requested_address, false);
}
ReservedSpace::ReservedSpace(size_t size, size_t alignment,
bool large,
bool executable) {
- initialize(size, alignment, large, NULL, 0, executable);
+ initialize(size, alignment, large, NULL, executable);
}
// Helper method.
@@ -91,7 +89,6 @@
void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
char* requested_address,
- const size_t noaccess_prefix,
bool executable) {
const size_t granularity = os::vm_allocation_granularity();
assert((size & (granularity - 1)) == 0,
@@ -103,10 +100,6 @@
alignment = MAX2(alignment, (size_t)os::vm_page_size());
- // Assert that if noaccess_prefix is used, it is the same as alignment.
- assert(noaccess_prefix == 0 ||
- noaccess_prefix == alignment, "noaccess prefix wrong");
-
_base = NULL;
_size = 0;
_special = false;
@@ -122,11 +115,6 @@
bool special = large && !os::can_commit_large_page_memory();
char* base = NULL;
- if (requested_address != 0) {
- requested_address -= noaccess_prefix; // adjust requested address
- assert(requested_address != NULL, "huge noaccess prefix?");
- }
-
if (special) {
base = os::reserve_memory_special(size, alignment, requested_address, executable);
@@ -176,7 +164,7 @@
if (base == NULL) return;
// Check alignment constraints
- if ((((size_t)base + noaccess_prefix) & (alignment - 1)) != 0) {
+ if ((((size_t)base) & (alignment - 1)) != 0) {
// Base not aligned, retry
if (!os::release_memory(base, size)) fatal("os::release_memory failed");
// Make sure that size is aligned
@@ -197,16 +185,6 @@
_base = base;
_size = size;
_alignment = alignment;
- _noaccess_prefix = noaccess_prefix;
-
- // Assert that if noaccess_prefix is used, it is the same as alignment.
- assert(noaccess_prefix == 0 ||
- noaccess_prefix == _alignment, "noaccess prefix wrong");
-
- assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base,
- "area must be distinguishable from marks for mark-sweep");
- assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size],
- "area must be distinguishable from marks for mark-sweep");
}
@@ -276,54 +254,336 @@
_base = NULL;
_size = 0;
_noaccess_prefix = 0;
+ _alignment = 0;
_special = false;
_executable = false;
}
}
-void ReservedSpace::protect_noaccess_prefix(const size_t size) {
- assert( (_noaccess_prefix != 0) == (UseCompressedOops && _base != NULL &&
- (Universe::narrow_oop_base() != NULL) &&
- Universe::narrow_oop_use_implicit_null_checks()),
- "noaccess_prefix should be used only with non zero based compressed oops");
+static size_t noaccess_prefix_size(size_t alignment) {
+ return lcm(os::vm_page_size(), alignment);
+}
- // If there is no noaccess prefix, return.
- if (_noaccess_prefix == 0) return;
+void ReservedHeapSpace::establish_noaccess_prefix() {
+ assert(_alignment >= (size_t)os::vm_page_size(), "must be at least page size big");
+ _noaccess_prefix = noaccess_prefix_size(_alignment);
- assert(_noaccess_prefix >= (size_t)os::vm_page_size(),
- "must be at least page size big");
-
- // Protect memory at the base of the allocated region.
- // If special, the page was committed (only matters on windows)
- if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE,
- _special)) {
- fatal("cannot protect protection page");
- }
- if (PrintCompressedOopsMode) {
- tty->cr();
- tty->print_cr("Protected page at the reserved heap base: " PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix);
+ if (base() && base() + _size > (char *)OopEncodingHeapMax) {
+ if (true
+ WIN64_ONLY(&& !UseLargePages)
+ AIX_ONLY(&& os::vm_page_size() != SIZE_64K)) {
+ // Protect memory at the base of the allocated region.
+ // If special, the page was committed (only matters on windows)
+ if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE, _special)) {
+ fatal("cannot protect protection page");
+ }
+ if (PrintCompressedOopsMode) {
+ tty->cr();
+ tty->print_cr("Protected page at the reserved heap base: "
+ PTR_FORMAT " / " INTX_FORMAT " bytes", _base, _noaccess_prefix);
+ }
+ assert(Universe::narrow_oop_use_implicit_null_checks() == true, "not initialized?");
+ } else {
+ Universe::set_narrow_oop_use_implicit_null_checks(false);
+ }
}
_base += _noaccess_prefix;
_size -= _noaccess_prefix;
- assert((size == _size) && ((uintptr_t)_base % _alignment == 0),
- "must be exactly of required size and alignment");
+ assert(((uintptr_t)_base % _alignment == 0), "must be exactly of required alignment");
+}
+
+// Tries to allocate memory of size 'size' at address requested_address with alignment 'alignment'.
+// Does not check whether the reserved memory actually is at requested_address, as the memory returned
+// might still fulfill the wishes of the caller.
+// Assures the memory is aligned to 'alignment'.
+// NOTE: If ReservedHeapSpace already points to some reserved memory this is freed, first.
+void ReservedHeapSpace::try_reserve_heap(size_t size,
+ size_t alignment,
+ bool large,
+ char* requested_address) {
+ if (_base != NULL) {
+ // We tried before, but we didn't like the address delivered.
+ release();
+ }
+
+ // If OS doesn't support demand paging for large page memory, we need
+ // to use reserve_memory_special() to reserve and pin the entire region.
+ bool special = large && !os::can_commit_large_page_memory();
+ char* base = NULL;
+
+ if (PrintCompressedOopsMode && Verbose) {
+ tty->print("Trying to allocate at address " PTR_FORMAT " heap of size " PTR_FORMAT ".\n",
+ requested_address, (address)size);
+ }
+
+ if (special) {
+ base = os::reserve_memory_special(size, alignment, requested_address, false);
+
+ if (base != NULL) {
+ // Check alignment constraints.
+ assert((uintptr_t) base % alignment == 0,
+ err_msg("Large pages returned a non-aligned address, base: "
+ PTR_FORMAT " alignment: " PTR_FORMAT,
+ base, (void*)(uintptr_t)alignment));
+ _special = true;
+ }
+ }
+
+ if (base == NULL) {
+ // Failed; try to reserve regular memory below
+ if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) ||
+ !FLAG_IS_DEFAULT(LargePageSizeInBytes))) {
+ if (PrintCompressedOopsMode) {
+ tty->cr();
+ tty->print_cr("Reserve regular memory without large pages.");
+ }
+ }
+
+ // Optimistically assume that the OSes returns an aligned base pointer.
+ // When reserving a large address range, most OSes seem to align to at
+ // least 64K.
+
+ // If the memory was requested at a particular address, use
+ // os::attempt_reserve_memory_at() to avoid over mapping something
+ // important. If available space is not detected, return NULL.
+
+ if (requested_address != 0) {
+ base = os::attempt_reserve_memory_at(size, requested_address);
+ } else {
+ base = os::reserve_memory(size, NULL, alignment);
+ }
+ }
+ if (base == NULL) { return; }
+
+ // Done
+ _base = base;
+ _size = size;
+ _alignment = alignment;
+
+ // Check alignment constraints
+ if ((((size_t)base) & (alignment - 1)) != 0) {
+ // Base not aligned, retry.
+ release();
+ }
+}
+
+void ReservedHeapSpace::try_reserve_range(char *highest_start,
+ char *lowest_start,
+ size_t attach_point_alignment,
+ char *aligned_heap_base_min_address,
+ char *upper_bound,
+ size_t size,
+ size_t alignment,
+ bool large) {
+ const size_t attach_range = highest_start - lowest_start;
+ // Cap num_attempts at possible number.
+ // At least one is possible even for 0 sized attach range.
+ const uint64_t num_attempts_possible = (attach_range / attach_point_alignment) + 1;
+ const uint64_t num_attempts_to_try = MIN2((uint64_t)HeapSearchSteps, num_attempts_possible);
+
+ const size_t stepsize = (attach_range == 0) ? // Only one try.
+ (size_t) highest_start : align_size_up(attach_range / num_attempts_to_try, attach_point_alignment);
+
+ // Try attach points from top to bottom.
+ char* attach_point = highest_start;
+ while (attach_point >= lowest_start &&
+ attach_point <= highest_start && // Avoid wrap around.
+ ((_base == NULL) ||
+ (_base < aligned_heap_base_min_address || _base + size > upper_bound))) {
+ try_reserve_heap(size, alignment, large, attach_point);
+ attach_point -= stepsize;
+ }
}
-ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment,
- bool large, char* requested_address) :
- ReservedSpace(size, alignment, large,
- requested_address,
- (UseCompressedOops && (Universe::narrow_oop_base() != NULL) &&
- Universe::narrow_oop_use_implicit_null_checks()) ?
- lcm(os::vm_page_size(), alignment) : 0) {
+#define SIZE_64K ((uint64_t) UCONST64( 0x10000))
+#define SIZE_256M ((uint64_t) UCONST64( 0x10000000))
+#define SIZE_32G ((uint64_t) UCONST64( 0x800000000))
+
+// Helper for heap allocation. Returns an array with addresses
+// (OS-specific) which are suited for disjoint base mode. Array is
+// NULL terminated.
+static char** get_attach_addresses_for_disjoint_mode() {
+ static uint64_t addresses[] = {
+ 2 * SIZE_32G,
+ 3 * SIZE_32G,
+ 4 * SIZE_32G,
+ 8 * SIZE_32G,
+ 10 * SIZE_32G,
+ 1 * SIZE_64K * SIZE_32G,
+ 2 * SIZE_64K * SIZE_32G,
+ 3 * SIZE_64K * SIZE_32G,
+ 4 * SIZE_64K * SIZE_32G,
+ 16 * SIZE_64K * SIZE_32G,
+ 32 * SIZE_64K * SIZE_32G,
+ 34 * SIZE_64K * SIZE_32G,
+ 0
+ };
+
+ // Sort out addresses smaller than HeapBaseMinAddress. This assumes
+ // the array is sorted.
+ uint i = 0;
+ while (addresses[i] != 0 &&
+ (addresses[i] < OopEncodingHeapMax || addresses[i] < HeapBaseMinAddress)) {
+ i++;
+ }
+ uint start = i;
+
+ // Avoid more steps than requested.
+ i = 0;
+ while (addresses[start+i] != 0) {
+ if (i == HeapSearchSteps) {
+ addresses[start+i] = 0;
+ break;
+ }
+ i++;
+ }
+
+ return (char**) &addresses[start];
+}
+
+void ReservedHeapSpace::initialize_compressed_heap(const size_t size, size_t alignment, bool large) {
+ guarantee(size + noaccess_prefix_size(alignment) <= OopEncodingHeapMax,
+ "can not allocate compressed oop heap for this size");
+ guarantee(alignment == MAX2(alignment, (size_t)os::vm_page_size()), "alignment too small");
+ assert(HeapBaseMinAddress > 0, "sanity");
+
+ const size_t granularity = os::vm_allocation_granularity();
+ assert((size & (granularity - 1)) == 0,
+ "size not aligned to os::vm_allocation_granularity()");
+ assert((alignment & (granularity - 1)) == 0,
+ "alignment not aligned to os::vm_allocation_granularity()");
+ assert(alignment == 0 || is_power_of_2((intptr_t)alignment),
+ "not a power of 2");
+
+ // The necessary attach point alignment for generated wish addresses.
+ // This is needed to increase the chance of attaching for mmap and shmat.
+ const size_t os_attach_point_alignment =
+ AIX_ONLY(SIZE_256M) // Known shm boundary alignment.
+ NOT_AIX(os::vm_allocation_granularity());
+ const size_t attach_point_alignment = lcm(alignment, os_attach_point_alignment);
+
+ char *aligned_heap_base_min_address = (char *)align_ptr_up((void *)HeapBaseMinAddress, alignment);
+ size_t noaccess_prefix = ((aligned_heap_base_min_address + size) > (char*)OopEncodingHeapMax) ?
+ noaccess_prefix_size(alignment) : 0;
+
+ // Attempt to alloc at user-given address.
+ if (!FLAG_IS_DEFAULT(HeapBaseMinAddress)) {
+ try_reserve_heap(size + noaccess_prefix, alignment, large, aligned_heap_base_min_address);
+ if (_base != aligned_heap_base_min_address) { // Enforce this exact address.
+ release();
+ }
+ }
+
+ // Keep heap at HeapBaseMinAddress.
+ if (_base == NULL) {
+
+ // Try to allocate the heap at addresses that allow efficient oop compression.
+ // Different schemes are tried, in order of decreasing optimization potential.
+ //
+ // For this, try_reserve_heap() is called with the desired heap base addresses.
+ // A call into the os layer to allocate at a given address can return memory
+ // at a different address than requested. Still, this might be memory at a useful
+ // address. try_reserve_heap() always returns this allocated memory, as only here
+ // the criteria for a good heap are checked.
+
+ // Attempt to allocate so that we can run without base and scale (32-Bit unscaled compressed oops).
+ // Give it several tries from top of range to bottom.
+ if (aligned_heap_base_min_address + size <= (char *)UnscaledOopHeapMax) {
+
+ // Calc address range within we try to attach (range of possible start addresses).
+ char* const highest_start = (char *)align_ptr_down((char *)UnscaledOopHeapMax - size, attach_point_alignment);
+ char* const lowest_start = (char *)align_ptr_up ( aligned_heap_base_min_address , attach_point_alignment);
+ try_reserve_range(highest_start, lowest_start, attach_point_alignment,
+ aligned_heap_base_min_address, (char *)UnscaledOopHeapMax, size, alignment, large);
+ }
+
+ // zerobased: Attempt to allocate in the lower 32G.
+ // But leave room for the compressed class pointers, which is allocated above
+ // the heap.
+ char *zerobased_max = (char *)OopEncodingHeapMax;
+ // For small heaps, save some space for compressed class pointer
+ // space so it can be decoded with no base.
+ if (UseCompressedClassPointers && !UseSharedSpaces &&
+ OopEncodingHeapMax <= KlassEncodingMetaspaceMax) {
+ const size_t class_space = align_size_up(CompressedClassSpaceSize, alignment);
+ zerobased_max = (char *)OopEncodingHeapMax - class_space;
+ }
+
+ // Give it several tries from top of range to bottom.
+ if (aligned_heap_base_min_address + size <= zerobased_max && // Zerobased theoretical possible.
+ ((_base == NULL) || // No previous try succeeded.
+ (_base + size > zerobased_max))) { // Unscaled delivered an arbitrary address.
+
+ // Calc address range within we try to attach (range of possible start addresses).
+ char *const highest_start = (char *)align_ptr_down(zerobased_max - size, attach_point_alignment);
+ // SS10 and SS12u1 cannot compile "(char *)UnscaledOopHeapMax - size" on solaris sparc 32-bit:
+ // "Cannot use int to initialize char*." Introduce aux variable.
+ char *unscaled_end = (char *)UnscaledOopHeapMax;
+ unscaled_end -= size;
+ char *lowest_start = (size < UnscaledOopHeapMax) ?
+ MAX2(unscaled_end, aligned_heap_base_min_address) : aligned_heap_base_min_address;
+ lowest_start = (char *)align_ptr_up(lowest_start, attach_point_alignment);
+ try_reserve_range(highest_start, lowest_start, attach_point_alignment,
+ aligned_heap_base_min_address, zerobased_max, size, alignment, large);
+ }
+
+ // Now we go for heaps with base != 0. We need a noaccess prefix to efficiently
+ // implement null checks.
+ noaccess_prefix = noaccess_prefix_size(alignment);
+
+ // Try to attach at addresses that are aligned to OopEncodingHeapMax. Disjointbase mode.
+ char** addresses = get_attach_addresses_for_disjoint_mode();
+ int i = 0;
+ while (addresses[i] && // End of array not yet reached.
+ ((_base == NULL) || // No previous try succeeded.
+ (_base + size > (char *)OopEncodingHeapMax && // Not zerobased or unscaled address.
+ !Universe::is_disjoint_heap_base_address((address)_base)))) { // Not disjoint address.
+ char* const attach_point = addresses[i];
+ assert(attach_point >= aligned_heap_base_min_address, "Flag support broken");
+ try_reserve_heap(size + noaccess_prefix, alignment, large, attach_point);
+ i++;
+ }
+
+ // Last, desperate try without any placement.
+ if (_base == NULL) {
+ if (PrintCompressedOopsMode && Verbose) {
+ tty->print("Trying to allocate at address NULL heap of size " PTR_FORMAT ".\n", (address)size + noaccess_prefix);
+ }
+ initialize(size + noaccess_prefix, alignment, large, NULL, false);
+ }
+ }
+}
+
+ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment, bool large) : ReservedSpace() {
+
+ if (size == 0) {
+ return;
+ }
+
+ // Heap size should be aligned to alignment, too.
+ guarantee(is_size_aligned(size, alignment), "set by caller");
+
+ if (UseCompressedOops) {
+ initialize_compressed_heap(size, alignment, large);
+ if (_size > size) {
+ // We allocated heap with noaccess prefix.
+ // It can happen we get a zerobased/unscaled heap with noaccess prefix,
+ // if we had to try at arbitrary address.
+ establish_noaccess_prefix();
+ }
+ } else {
+ initialize(size, alignment, large, NULL, false);
+ }
+
+ assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base,
+ "area must be distinguishable from marks for mark-sweep");
+ assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size],
+ "area must be distinguishable from marks for mark-sweep");
+
if (base() > 0) {
MemTracker::record_virtual_memory_type((address)base(), mtJavaHeap);
}
-
- // Only reserved space for the java heap should have a noaccess_prefix
- // if using compressed oops.
- protect_noaccess_prefix(size);
}
// Reserve space for code segment. Same as Java heap only we mark this as
@@ -791,8 +1051,7 @@
ReservedSpace rs(size, // size
alignment, // alignment
UseLargePages, // large
- NULL, // requested_address
- 0); // noacces_prefix
+ (char *)NULL); // requested_address
test_log(" rs.special() == %d", rs.special());
--- a/hotspot/src/share/vm/runtime/virtualspace.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/runtime/virtualspace.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -31,33 +31,29 @@
class ReservedSpace VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
- private:
+ protected:
char* _base;
size_t _size;
size_t _noaccess_prefix;
size_t _alignment;
bool _special;
+ private:
bool _executable;
// ReservedSpace
ReservedSpace(char* base, size_t size, size_t alignment, bool special,
bool executable);
+ protected:
void initialize(size_t size, size_t alignment, bool large,
char* requested_address,
- const size_t noaccess_prefix,
bool executable);
- protected:
- // Create protection page at the beginning of the space.
- void protect_noaccess_prefix(const size_t size);
-
public:
// Constructor
ReservedSpace();
ReservedSpace(size_t size);
ReservedSpace(size_t size, size_t alignment, bool large,
- char* requested_address = NULL,
- const size_t noaccess_prefix = 0);
+ char* requested_address = NULL);
ReservedSpace(size_t size, size_t alignment, bool large, bool executable);
// Accessors
@@ -98,12 +94,23 @@
return last_part(partition_size, alignment());
}
-// Class encapsulating behavior specific of memory space reserved for Java heap
+// Class encapsulating behavior specific of memory space reserved for Java heap.
class ReservedHeapSpace : public ReservedSpace {
-public:
- // Constructor
- ReservedHeapSpace(size_t size, size_t forced_base_alignment,
- bool large, char* requested_address);
+ private:
+ void try_reserve_heap(size_t size, size_t alignment, bool large,
+ char *requested_address);
+ void try_reserve_range(char *highest_start, char *lowest_start,
+ size_t attach_point_alignment, char *aligned_HBMA,
+ char *upper_bound, size_t size, size_t alignment, bool large);
+ void initialize_compressed_heap(const size_t size, size_t alignment, bool large);
+ // Create protection page at the beginning of the space.
+ void establish_noaccess_prefix();
+ public:
+ // Constructor. Tries to find a heap that is good for compressed oops.
+ ReservedHeapSpace(size_t size, size_t forced_base_alignment, bool large);
+ // Returns the base to be used for compression, i.e. so that null can be
+ // encoded safely and implicit null checks can work.
+ char *compressed_oop_base() { return _base - _noaccess_prefix; }
};
// Class encapsulating behavior specific memory space for Code
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -2559,6 +2559,8 @@
/**********************/ \
/* frame */ \
/**********************/ \
+ NOT_ZERO(PPC64_ONLY(declare_constant(frame::abi_minframe_size))) \
+ NOT_ZERO(PPC64_ONLY(declare_constant(frame::entry_frame_locals_size))) \
\
NOT_ZERO(X86_ONLY(declare_constant(frame::entry_frame_call_wrapper_offset))) \
declare_constant(frame::pc_return_offset) \
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -100,6 +100,7 @@
template(RotateGCLog) \
template(WhiteBoxOperation) \
template(ClassLoaderStatsOperation) \
+ template(DumpHashtable) \
template(MarkActiveNMethods) \
template(PrintCompileQueue) \
template(PrintCodeList) \
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Fri Jan 16 12:33:47 2015 -0800
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/classLoaderStats.hpp"
+#include "classfile/compactHashtable.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
@@ -56,6 +57,8 @@
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
+ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SymboltableDCmd>(full_export, true, false));
+ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<StringtableDCmd>(full_export, true, false));
#endif // INCLUDE_SERVICES
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RotateGCLogDCmd>(full_export, true, false));
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -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
@@ -124,9 +124,6 @@
extern int BytesPerHeapOop;
extern int BitsPerHeapOop;
-// Oop encoding heap max
-extern uint64_t OopEncodingHeapMax;
-
const int BitsPerJavaInteger = 32;
const int BitsPerJavaLong = 64;
const int BitsPerSize_t = size_tSize * BitsPerByte;
@@ -195,7 +192,6 @@
return (byte_size + (HeapWordSize-1)) >> LogHeapWordSize;
}
-
const size_t K = 1024;
const size_t M = K*K;
const size_t G = M*K;
@@ -397,8 +393,17 @@
const int KlassAlignmentInBytes = 1 << LogKlassAlignmentInBytes;
const int KlassAlignment = KlassAlignmentInBytes / HeapWordSize;
-// Klass encoding metaspace max size
-const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlassAlignmentInBytes;
+// Maximal size of heap where unscaled compression can be used. Also upper bound
+// for heap placement: 4GB.
+const uint64_t UnscaledOopHeapMax = (uint64_t(max_juint) + 1);
+// Maximal size of heap where compressed oops can be used. Also upper bound for heap
+// placement for zero based compression algorithm: UnscaledOopHeapMax << LogMinObjAlignmentInBytes.
+extern uint64_t OopEncodingHeapMax;
+
+// Maximal size of compressed class space. Above this limit compression is not possible.
+// Also upper bound for placement of zero based class space. (Class space is further limited
+// to be < 3G, see arguments.cpp.)
+const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlassAlignmentInBytes;
// Machine dependent stuff
--- a/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_xlc.hpp Fri Jan 16 12:33:47 2015 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright 2012, 2013 SAP AG. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -172,21 +172,21 @@
#define offset_of(klass,field) (size_t)((intx)&(((klass*)16)->field) - 16)
// Some constant sizes used throughout the AIX port
-#define SIZE_1K ((uint64_t) 0x400ULL)
-#define SIZE_4K ((uint64_t) 0x1000ULL)
-#define SIZE_64K ((uint64_t) 0x10000ULL)
-#define SIZE_1M ((uint64_t) 0x100000ULL)
-#define SIZE_4M ((uint64_t) 0x400000ULL)
-#define SIZE_8M ((uint64_t) 0x800000ULL)
-#define SIZE_16M ((uint64_t) 0x1000000ULL)
-#define SIZE_256M ((uint64_t) 0x10000000ULL)
-#define SIZE_1G ((uint64_t) 0x40000000ULL)
-#define SIZE_2G ((uint64_t) 0x80000000ULL)
-#define SIZE_4G ((uint64_t) 0x100000000ULL)
-#define SIZE_16G ((uint64_t) 0x400000000ULL)
-#define SIZE_32G ((uint64_t) 0x800000000ULL)
-#define SIZE_64G ((uint64_t) 0x1000000000ULL)
-#define SIZE_1T ((uint64_t) 0x10000000000ULL)
+#define SIZE_1K ((uint64_t) UCONST64( 0x400))
+#define SIZE_4K ((uint64_t) UCONST64( 0x1000))
+#define SIZE_64K ((uint64_t) UCONST64( 0x10000))
+#define SIZE_1M ((uint64_t) UCONST64( 0x100000))
+#define SIZE_4M ((uint64_t) UCONST64( 0x400000))
+#define SIZE_8M ((uint64_t) UCONST64( 0x800000))
+#define SIZE_16M ((uint64_t) UCONST64( 0x1000000))
+#define SIZE_256M ((uint64_t) UCONST64( 0x10000000))
+#define SIZE_1G ((uint64_t) UCONST64( 0x40000000))
+#define SIZE_2G ((uint64_t) UCONST64( 0x80000000))
+#define SIZE_4G ((uint64_t) UCONST64( 0x100000000))
+#define SIZE_16G ((uint64_t) UCONST64( 0x400000000))
+#define SIZE_32G ((uint64_t) UCONST64( 0x800000000))
+#define SIZE_64G ((uint64_t) UCONST64( 0x1000000000))
+#define SIZE_1T ((uint64_t) UCONST64(0x10000000000))
#endif // SHARE_VM_UTILITIES_GLOBALDEFINITIONS_XLC_HPP
--- a/hotspot/test/TEST.groups Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/TEST.groups Fri Jan 16 12:33:47 2015 -0800
@@ -145,6 +145,7 @@
gc/survivorAlignment \
runtime/InternalApi/ThreadCpuTimesDeadlock.java \
serviceability/threads/TestFalseDeadLock.java \
+ compiler/codecache/jmx
# Compact 2 adds full VM tests
compact2 = \
@@ -413,6 +414,12 @@
gc/ \
-gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java
+hotspot_gc_closed = \
+ sanity/ExecuteInternalVMTests.java
+
+hotspot_gc_gcold = \
+ stress/gc/TestGCOld.java
+
hotspot_runtime = \
runtime/ \
-runtime/6888954/vmerrors.sh \
@@ -444,6 +451,8 @@
:hotspot_compiler_3 \
:hotspot_compiler_closed \
:hotspot_gc \
+ :hotspot_gc_closed \
+ :hotspot_gc_gcold \
:hotspot_runtime \
:hotspot_runtime_closed \
:hotspot_serviceability
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/arraycopy/TestArrayCopyMacro.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,79 @@
+/*
+ * 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 7173584
+ * @summary arraycopy as macro node
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayCopyMacro
+ *
+ */
+
+public class TestArrayCopyMacro {
+ static class A {
+ }
+
+ // In its own method so profiling reports both branches taken
+ static Object m2(Object o1, Object o2, int i) {
+ if (i == 4) {
+ return o1;
+ }
+ return o2;
+ }
+
+ static Object m1(A[] src, Object dest) {
+ int i = 1;
+
+ // won't be optimized out until after parsing
+ for (; i < 3; i *= 4) {
+ }
+ dest = m2(new A[10], dest, i);
+
+ // dest is new array here but C2 picks the "disjoint" stub
+ // only if stub to call is decided after parsing
+ System.arraycopy(src, 0, dest, 0, 10);
+ return dest;
+ }
+
+ public static void main(String[] args) {
+ A[] array_src = new A[10];
+
+ for (int i = 0; i < array_src.length; i++) {
+ array_src[i] = new A();
+ }
+
+ for (int i = 0; i < 20000; i++) {
+ m2(null, null, 0);
+ }
+
+ for (int i = 0; i < 20000; i++) {
+ Object[] array_dest = (Object[])m1(array_src, null);
+
+ for (int j = 0; j < array_src.length; j++) {
+ if (array_dest[j] != array_src[j]) {
+ throw new RuntimeException("copy failed at index " + j + " src = " + array_src[j] + " dest = " + array_dest[j]);
+ }
+ }
+ }
+ }
+}
--- a/hotspot/test/compiler/arraycopy/TestArrayOfNoTypeCheck.java Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8055910
- * @summary Arrays.copyOf doesn't perform subtype check
- * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayOfNoTypeCheck
- *
- */
-
-import java.util.Arrays;
-
-public class TestArrayOfNoTypeCheck {
-
- static class A {
- }
-
- static class B extends A {
- }
-
- static B[] test(A[] arr) {
- return Arrays.copyOf(arr, 10, B[].class);
- }
-
- static public void main(String[] args) {
- A[] arr = new A[20];
- for (int i = 0; i < 20000; i++) {
- test(arr);
- }
- A[] arr2 = new A[20];
- arr2[0] = new A();
- boolean exception = false;
- try {
- test(arr2);
- } catch (ArrayStoreException ase) {
- exception = true;
- }
- if (!exception) {
- throw new RuntimeException("TEST FAILED: ArrayStoreException not thrown");
- }
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/arraycopy/TestArraysCopyOfNoTypeCheck.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8055910
+ * @summary Arrays.copyOf doesn't perform subtype check
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArraysCopyOfNoTypeCheck
+ *
+ */
+
+import java.util.Arrays;
+
+public class TestArraysCopyOfNoTypeCheck {
+
+ static class A {
+ }
+
+ static class B extends A {
+ }
+
+ static B[] test(A[] arr) {
+ return Arrays.copyOf(arr, 10, B[].class);
+ }
+
+ static public void main(String[] args) {
+ A[] arr = new A[20];
+ for (int i = 0; i < 20000; i++) {
+ test(arr);
+ }
+ A[] arr2 = new A[20];
+ arr2[0] = new A();
+ boolean exception = false;
+ try {
+ test(arr2);
+ } catch (ArrayStoreException ase) {
+ exception = true;
+ }
+ if (!exception) {
+ throw new RuntimeException("TEST FAILED: ArrayStoreException not thrown");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/arraycopy/TestInstanceCloneAsLoadsStores.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,342 @@
+/*
+ * 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 6700100
+ * @summary small instance clone as loads/stores
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestInstanceCloneAsLoadsStores::m* TestInstanceCloneAsLoadsStores
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestInstanceCloneAsLoadsStores::m* -XX:+IgnoreUnrecognizedVMOptions -XX:+StressArrayCopyMacroNode TestInstanceCloneAsLoadsStores
+ *
+ */
+
+import java.lang.reflect.*;
+import java.util.*;
+
+public class TestInstanceCloneAsLoadsStores {
+ static class Base implements Cloneable {
+ void initialize(Class c, int i) {
+ for (Field f : c.getDeclaredFields()) {
+ setVal(f, i);
+ i++;
+ }
+ if (c != Base.class) {
+ initialize(c.getSuperclass(), i);
+ }
+ }
+
+ Base() {
+ initialize(getClass(), 0);
+ }
+
+ void setVal(Field f, int i) {
+ try {
+ if (f.getType() == int.class) {
+ f.setInt(this, i);
+ return;
+ } else if (f.getType() == short.class) {
+ f.setShort(this, (short)i);
+ return;
+ } else if (f.getType() == byte.class) {
+ f.setByte(this, (byte)i);
+ return;
+ } else if (f.getType() == long.class) {
+ f.setLong(this, i);
+ return;
+ }
+ } catch(IllegalAccessException iae) {
+ throw new RuntimeException("Getting fields failed");
+ }
+ throw new RuntimeException("unexpected field type");
+ }
+
+ int getVal(Field f) {
+ try {
+ if (f.getType() == int.class) {
+ return f.getInt(this);
+ } else if (f.getType() == short.class) {
+ return (int)f.getShort(this);
+ } else if (f.getType() == byte.class) {
+ return (int)f.getByte(this);
+ } else if (f.getType() == long.class) {
+ return (int)f.getLong(this);
+ }
+ } catch(IllegalAccessException iae) {
+ throw new RuntimeException("Setting fields failed");
+ }
+ throw new RuntimeException("unexpected field type");
+ }
+
+ boolean fields_equal(Class c, Base o) {
+ for (Field f : c.getDeclaredFields()) {
+ if (getVal(f) != o.getVal(f)) {
+ return false;
+ }
+ }
+ if (c != Base.class) {
+ return fields_equal(c.getSuperclass(), o);
+ }
+ return true;
+ }
+
+ public boolean equals(Object obj) {
+ return fields_equal(getClass(), (Base)obj);
+ }
+
+ String print_fields(Class c, String s) {
+ for (Field f : c.getDeclaredFields()) {
+ if (s != "") {
+ s += "\n";
+ }
+ s = s + f + " = " + getVal(f);
+ }
+ if (c != Base.class) {
+ return print_fields(c.getSuperclass(), s);
+ }
+ return s;
+ }
+
+ public String toString() {
+ return print_fields(getClass(), "");
+ }
+
+ int fields_sum(Class c, int s) {
+ for (Field f : c.getDeclaredFields()) {
+ s += getVal(f);
+ }
+ if (c != Base.class) {
+ return fields_sum(c.getSuperclass(), s);
+ }
+ return s;
+ }
+
+ public int sum() {
+ return fields_sum(getClass(), 0);
+ }
+
+ }
+
+ static class A extends Base {
+ int i1;
+ int i2;
+ int i3;
+ int i4;
+ int i5;
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+ }
+
+ static class B extends A {
+ int i6;
+ }
+
+ static final class D extends Base {
+ byte i1;
+ short i2;
+ long i3;
+ int i4;
+ int i5;
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+ }
+
+ static final class E extends Base {
+ int i1;
+ int i2;
+ int i3;
+ int i4;
+ int i5;
+ int i6;
+ int i7;
+ int i8;
+ int i9;
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+ }
+
+ static final class F extends Base {
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+ }
+
+ static class G extends Base {
+ int i1;
+ int i2;
+ int i3;
+
+ public Object myclone() throws CloneNotSupportedException {
+ return clone();
+ }
+ }
+
+ static class H extends G {
+ int i4;
+ int i5;
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+ }
+
+ static class J extends Base {
+ int i1;
+ int i2;
+ int i3;
+
+ public Object myclone() throws CloneNotSupportedException {
+ return clone();
+ }
+ }
+
+ static class K extends J {
+ int i4;
+ int i5;
+ }
+
+ // Should be compiled as loads/stores
+ static Object m1(D src) throws CloneNotSupportedException {
+ return src.clone();
+ }
+
+ // Should be compiled as adds of src (dest allocation eliminated)
+ static int m2(D src) throws CloneNotSupportedException {
+ D dest = (D)src.clone();
+ return dest.i1 + dest.i2 + ((int)dest.i3) + dest.i4 + dest.i5;
+ }
+
+ // Should be compiled as arraycopy stub call (object too large)
+ static int m3(E src) throws CloneNotSupportedException {
+ E dest = (E)src.clone();
+ return dest.i1 + dest.i2 + dest.i3 + dest.i4 + dest.i5 +
+ dest.i6 + dest.i7 + dest.i8 + dest.i9;
+ }
+
+ // Need profiling on src's type to be able to know number of
+ // fields. Cannot clone as loads/stores if compile doesn't use it.
+ static Object m4(A src) throws CloneNotSupportedException {
+ return src.clone();
+ }
+
+ // Same as above but should optimize out dest allocation
+ static int m5(A src) throws CloneNotSupportedException {
+ A dest = (A)src.clone();
+ return dest.i1 + dest.i2 + dest.i3 + dest.i4 + dest.i5;
+ }
+
+ // Check that if we have no fields to clone we do fine
+ static Object m6(F src) throws CloneNotSupportedException {
+ return src.clone();
+ }
+
+ // With virtual call to clone: clone inlined from profling which
+ // gives us exact type of src so we can clone it with
+ // loads/stores.
+ static G m7(G src) throws CloneNotSupportedException {
+ return (G)src.myclone();
+ }
+
+ // Virtual call to clone but single target: exact type unknown,
+ // clone intrinsic uses profiling to determine exact type and
+ // clone with loads/stores.
+ static J m8(J src) throws CloneNotSupportedException {
+ return (J)src.myclone();
+ }
+
+ final HashMap<String,Method> tests = new HashMap<>();
+ {
+ for (Method m : this.getClass().getDeclaredMethods()) {
+ if (m.getName().matches("m[0-9]+")) {
+ assert(Modifier.isStatic(m.getModifiers())) : m;
+ tests.put(m.getName(), m);
+ }
+ }
+ }
+
+ boolean success = true;
+
+ void doTest(Base src, String name) throws Exception {
+ Method m = tests.get(name);
+
+ for (int i = 0; i < 20000; i++) {
+ boolean failure = false;
+ Base res = null;
+ int s = 0;
+ if (m.getReturnType().isPrimitive()) {
+ s = (int)m.invoke(null, src);
+ failure = (s != src.sum());
+ } else {
+ res = (Base)m.invoke(null, src);
+ failure = !res.equals(src);
+ }
+ if (failure) {
+ System.out.println("Test " + name + " failed");
+ System.out.println("source: ");
+ System.out.println(src);
+ System.out.println("result: ");
+ if (m.getReturnType().isPrimitive()) {
+ System.out.println(s);
+ } else {
+ System.out.println(res);
+ }
+ success = false;
+ break;
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ TestInstanceCloneAsLoadsStores test = new TestInstanceCloneAsLoadsStores();
+
+ A a = new A();
+ B b = new B();
+ D d = new D();
+ E e = new E();
+ F f = new F();
+ G g = new G();
+ H h = new H();
+ J j = new J();
+ K k = new K();
+
+ test.doTest(d, "m1");
+ test.doTest(d, "m2");
+ test.doTest(e, "m3");
+ test.doTest(a, "m4");
+ test.doTest(a, "m5");
+ test.doTest(f, "m6");
+ test.doTest(g, "m7");
+ test.doTest(k, "m8");
+
+ if (!test.success) {
+ throw new RuntimeException("some tests failed");
+ }
+
+ }
+}
--- a/hotspot/test/compiler/ciReplay/TestSA.sh Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/ciReplay/TestSA.sh Fri Jan 16 12:33:47 2015 -0800
@@ -26,7 +26,7 @@
##
## @test
## @bug 8011675
-## @ignore 8031978
+## @ignore 8029528
## @summary testing of ciReplay with using generated by SA replay.txt
## @author igor.ignatyev@oracle.com
## @run shell TestSA.sh
@@ -69,7 +69,6 @@
echo "dumpreplaydata -a > ${replay_data}" | \
${JAVA} ${TESTOPTS} \
- -cp ${TESTJAVA}${FS}lib${FS}sa-jdi.jar \
sun.jvm.hotspot.CLHSDB ${JAVA} ${core_file}
if [ ! -s ${replay_data} ]
--- a/hotspot/test/compiler/ciReplay/common.sh Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/ciReplay/common.sh Fri Jan 16 12:33:47 2015 -0800
@@ -263,10 +263,10 @@
dir=`dirname $core_with_dir`
file=`basename $core_with_dir`
# add <core_path>/core.<pid> core
- core_locations="'$core_with_dir' '$file'"
+ core_locations='$core_with_dir' '$file'
if [ -n "${core_with_pid}" ]
then
- core_locations="$core_locations '$core_with_pid' '$dir${FS}$core_with_pid'"
+ core_locations=$core_locations '$core_with_pid' '$dir${FS}$core_with_pid'
fi
fi
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/TestSegmentedCodeCacheOption.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import com.oracle.java.testlibrary.ExitCode;
+import com.oracle.java.testlibrary.Platform;
+import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
+import common.CodeCacheOptions;
+import sun.hotspot.code.BlobType;
+
+/**
+ * @test
+ * @bug 8015774
+ * @summary Verify SegmentedCodeCache option's processing
+ * @library /testlibrary /../../test/lib
+ * @build TestSegmentedCodeCacheOption com.oracle.java.testlibrary.*
+ * @run main TestSegmentedCodeCacheOption
+ */
+public class TestSegmentedCodeCacheOption {
+ private static final String INT_MODE = "-Xint";
+ private static final String TIERED_COMPILATION = "TieredCompilation";
+ private static final String SEGMENTED_CODE_CACHE = "SegmentedCodeCache";
+ private static final String USE_SEGMENTED_CODE_CACHE
+ = CommandLineOptionTest.prepareBooleanFlag(SEGMENTED_CODE_CACHE,
+ true);
+ private static final long THRESHOLD_CC_SIZE_VALUE
+ = CodeCacheOptions.mB(240);
+ private static final long BELOW_THRESHOLD_CC_SIZE
+ = THRESHOLD_CC_SIZE_VALUE - CodeCacheOptions.mB(1);
+ private static final String[] UNEXPECTED_MESSAGES = new String[] {
+ ".*" + SEGMENTED_CODE_CACHE + ".*"
+ };
+
+
+ private static enum TestCase {
+ JVM_STARTUP {
+ @Override
+ public void run() throws Throwable {
+ // There should be no errors when we're trying to enable SCC ...
+ String testCaseWarningMessage = "JVM output should not contain "
+ + "any warnings related to " + SEGMENTED_CODE_CACHE;
+ String testCaseExitCodeMessage = "JVM should start without any "
+ + "issues with " + USE_SEGMENTED_CODE_CACHE;
+
+ CommandLineOptionTest.verifySameJVMStartup(
+ /* expectedMessages */ null, UNEXPECTED_MESSAGES,
+ testCaseExitCodeMessage, testCaseWarningMessage,
+ ExitCode.OK, USE_SEGMENTED_CODE_CACHE);
+ // ... and when we're trying to enable it w/o TieredCompilation
+ testCaseExitCodeMessage = "Disabled tiered compilation should "
+ + "not cause startup failure w/ "
+ + USE_SEGMENTED_CODE_CACHE;
+
+ CommandLineOptionTest.verifySameJVMStartup(
+ /* expectedMessages */ null, UNEXPECTED_MESSAGES,
+ testCaseExitCodeMessage, testCaseWarningMessage,
+ ExitCode.OK, USE_SEGMENTED_CODE_CACHE,
+ CommandLineOptionTest.prepareBooleanFlag(
+ TIERED_COMPILATION, false));
+ // ... and even w/ Xint.
+ testCaseExitCodeMessage = "It should be possible to use "
+ + USE_SEGMENTED_CODE_CACHE + " in interpreted mode "
+ + "without any errors.";
+
+ CommandLineOptionTest.verifyJVMStartup(
+ /* expected messages */ null, UNEXPECTED_MESSAGES,
+ testCaseExitCodeMessage, testCaseWarningMessage,
+ ExitCode.OK, false, INT_MODE, USE_SEGMENTED_CODE_CACHE);
+ }
+ },
+ OPTION_VALUES_GENERIC {
+ @Override
+ public void run() throws Throwable {
+ // SCC is disabled w/o TieredCompilation by default
+ String errorMessage = SEGMENTED_CODE_CACHE
+ + " should be disabled by default when tiered "
+ + "compilation is disabled";
+
+ CommandLineOptionTest.verifyOptionValueForSameVM(
+ SEGMENTED_CODE_CACHE, "false", errorMessage,
+ CommandLineOptionTest.prepareBooleanFlag(
+ TIERED_COMPILATION, false));
+ // SCC is disabled by default when ReservedCodeCacheSize is too
+ // small
+ errorMessage = String.format("%s should be disabled bu default "
+ + "when %s value is too small.", SEGMENTED_CODE_CACHE,
+ BlobType.All.sizeOptionName);
+
+ CommandLineOptionTest.verifyOptionValueForSameVM(
+ SEGMENTED_CODE_CACHE, "false", errorMessage,
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.All.sizeOptionName,
+ BELOW_THRESHOLD_CC_SIZE));
+ // SCC could be explicitly enabled w/ Xint
+ errorMessage = String.format("It should be possible to "
+ + "explicitly enable %s in interpreted mode.",
+ SEGMENTED_CODE_CACHE);
+
+ CommandLineOptionTest.verifyOptionValue(SEGMENTED_CODE_CACHE,
+ "true", errorMessage, false, INT_MODE,
+ USE_SEGMENTED_CODE_CACHE);
+ // SCC could be explicitly enabled w/o TieredCompilation and w/
+ // small ReservedCodeCacheSize value
+ errorMessage = String.format("It should be possible to "
+ + "explicitly enable %s with small %s and "
+ + "disabled tiered comp.", SEGMENTED_CODE_CACHE,
+ BlobType.All.sizeOptionName);
+
+ CommandLineOptionTest.verifyOptionValueForSameVM(
+ SEGMENTED_CODE_CACHE, "true", errorMessage,
+ CommandLineOptionTest.prepareBooleanFlag(
+ TIERED_COMPILATION, false),
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.All.sizeOptionName,
+ BELOW_THRESHOLD_CC_SIZE),
+ USE_SEGMENTED_CODE_CACHE);
+ }
+ },
+ OPTION_VALUES_SERVER_SPECIFIC {
+ @Override
+ public boolean isApplicable() {
+ return Platform.isServer() && Platform.isTieredSupported();
+ }
+
+ @Override
+ public void run() throws Throwable {
+ // SCC is enabled by default when TieredCompilation is on and
+ // ReservedCodeCacheSize is large enough
+ String errorMessage = String.format("Large enough %s and "
+ + "enabled tiered compilation should enable %s "
+ + "by default.", BlobType.All.sizeOptionName,
+ SEGMENTED_CODE_CACHE);
+
+ CommandLineOptionTest.verifyOptionValueForSameVM(
+ SEGMENTED_CODE_CACHE, "true", errorMessage,
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.All.sizeOptionName,
+ THRESHOLD_CC_SIZE_VALUE),
+ CommandLineOptionTest.prepareBooleanFlag(
+ TIERED_COMPILATION, true));
+ }
+ };
+
+ TestCase() {
+ }
+
+ public boolean isApplicable() {
+ return true;
+ }
+
+ public abstract void run() throws Throwable;
+ }
+
+ public static void main(String args[]) throws Throwable {
+ for (TestCase testCase : TestCase.values()) {
+ if (testCase.isApplicable()) {
+ System.out.println("Running test case: " + testCase.name());
+ testCase.run();
+ } else {
+ System.out.println("Test case skipped: " + testCase.name());
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/codeheapsize/CodeCacheFreeSpaceRunner.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package codeheapsize;
+
+import com.oracle.java.testlibrary.ExitCode;
+import com.oracle.java.testlibrary.Platform;
+import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
+import common.CodeCacheCLITestCase;
+import common.CodeCacheOptions;
+import sun.hotspot.code.BlobType;
+
+/**
+ * Test case runner aimed to verify that NonNMethodCodeHeapSize smaller than
+ * CodeCacheMinimumUseSpace cause JVM startup failure.
+ */
+public class CodeCacheFreeSpaceRunner implements CodeCacheCLITestCase.Runner {
+ private static final String CC_MIN_USE_SPACE = "CodeCacheMinimumUseSpace";
+ private static final String TOO_SMALL_NMETHOD_CH_ERROR
+ = "Invalid NonNMethodCodeHeapSize.*";
+ private static final long MULTIPLIER = Platform.isDebugBuild() ? 3L : 1L;
+ @Override
+ public void run(CodeCacheCLITestCase.Description testCaseDescription,
+ CodeCacheOptions options) throws Throwable {
+ long ccMinUseSpace = ((options.nonNmethods - 1) / MULTIPLIER + 1);
+
+ String exitCodeErrorMessage = String.format("JVM startup should fail "
+ + "if %s's value lower then %s.",
+ BlobType.NonNMethod.sizeOptionName, CC_MIN_USE_SPACE);
+ String vmOutputErrorMessage = String.format("JVM's output should "
+ + "contain appropriate error message when %s lower "
+ + "then %s.", BlobType.NonNMethod.sizeOptionName,
+ CC_MIN_USE_SPACE);
+
+ CommandLineOptionTest.verifySameJVMStartup(
+ new String[]{ TOO_SMALL_NMETHOD_CH_ERROR },
+ /* unexpected messages */ null,
+ exitCodeErrorMessage, vmOutputErrorMessage, ExitCode.FAIL,
+ testCaseDescription.getTestOptions(options,
+ CommandLineOptionTest.prepareNumericFlag(
+ CC_MIN_USE_SPACE, ccMinUseSpace + 1)));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/codeheapsize/GenericCodeHeapSizeRunner.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package codeheapsize;
+
+import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
+import common.CodeCacheCLITestCase;
+import common.CodeCacheOptions;
+import sun.hotspot.code.BlobType;
+
+/**
+ * Test case runner aimed to verify that all four options related to code cache
+ * sizing have correct values.
+ */
+public class GenericCodeHeapSizeRunner implements CodeCacheCLITestCase.Runner {
+ @Override
+ public void run(CodeCacheCLITestCase.Description testCaseDescription,
+ CodeCacheOptions options) throws Throwable {
+ CodeCacheOptions expectedValues
+ = options.mapOptions(testCaseDescription.involvedCodeHeaps);
+
+ CommandLineOptionTest.verifyOptionValueForSameVM(
+ BlobType.All.sizeOptionName,
+ Long.toString(expectedValues.reserved),
+ String.format("%s should have value %d.",
+ BlobType.All.sizeOptionName, expectedValues.reserved),
+ testCaseDescription.getTestOptions(options));
+
+ CommandLineOptionTest.verifyOptionValueForSameVM(
+ BlobType.NonNMethod.sizeOptionName,
+ Long.toString(expectedValues.nonNmethods),
+ String.format("%s should have value %d.",
+ BlobType.NonNMethod.sizeOptionName,
+ expectedValues.nonNmethods),
+ testCaseDescription.getTestOptions(options));
+
+ CommandLineOptionTest.verifyOptionValueForSameVM(
+ BlobType.MethodNonProfiled.sizeOptionName,
+ Long.toString(expectedValues.nonProfiled),
+ String.format("%s should have value %d.",
+ BlobType.MethodNonProfiled.sizeOptionName,
+ expectedValues.nonProfiled),
+ testCaseDescription.getTestOptions(options));
+
+ CommandLineOptionTest.verifyOptionValueForSameVM(
+ BlobType.MethodProfiled.sizeOptionName,
+ Long.toString(expectedValues.profiled),
+ String.format("%s should have value %d.",
+ BlobType.MethodProfiled.sizeOptionName,
+ expectedValues.profiled),
+ testCaseDescription.getTestOptions(options));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/codeheapsize/JVMStartupRunner.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package codeheapsize;
+
+import common.CodeCacheCLITestCase;
+import common.CodeCacheOptions;
+import com.oracle.java.testlibrary.ExitCode;
+import com.oracle.java.testlibrary.Utils;
+import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
+import sun.hotspot.code.BlobType;
+import java.util.Random;
+
+/**
+ * Test case runner aimed to verify option's consistency.
+ */
+public class JVMStartupRunner implements CodeCacheCLITestCase.Runner {
+ private static final String INCONSISTENT_CH_SIZES_ERROR
+ = "Invalid code heap sizes.*";
+
+ @Override
+ public void run(CodeCacheCLITestCase.Description testCaseDescription,
+ CodeCacheOptions options) throws Throwable {
+ // Everything should be fine when
+ // sum(all code heap sizes) == reserved CC size
+ CommandLineOptionTest.verifySameJVMStartup(/* expected messages */ null,
+ new String[]{ INCONSISTENT_CH_SIZES_ERROR },
+ "JVM startup should not fail with consistent code heap sizes",
+ "JVM output should not contain warning about inconsistent code "
+ + "heap sizes", ExitCode.OK, options.prepareOptions());
+
+ verifySingleInconsistentValue(options);
+ verifyAllInconsistentValues(options);
+ }
+
+ /**
+ * Verifies that if at least one of three options will have value, such
+ * that sum of all three values will be inconsistent, then JVM startup will
+ * fail.
+ */
+ private static void verifySingleInconsistentValue(CodeCacheOptions options)
+ throws Throwable {
+ verifyHeapSizesSum(options.reserved,
+ scaleCodeHeapSize(options.profiled), options.nonProfiled,
+ options.nonNmethods);
+ verifyHeapSizesSum(options.reserved, options.profiled,
+ scaleCodeHeapSize(options.nonProfiled), options.nonNmethods);
+ verifyHeapSizesSum(options.reserved, options.profiled,
+ options.nonProfiled, scaleCodeHeapSize(options.nonNmethods));
+ }
+
+ /**
+ * Verifies that if all three options will have values such that their sum
+ * is inconsistent with ReservedCodeCacheSize value, then JVM startup will
+ * fail.
+ */
+ private static void verifyAllInconsistentValues(CodeCacheOptions options)
+ throws Throwable {
+ long profiled = options.profiled;
+ long nonProfiled = options.nonProfiled;
+ long nonNMethods = options.nonNmethods;
+
+ while (options.reserved == profiled + nonProfiled + nonNMethods) {
+ profiled = scaleCodeHeapSize(profiled);
+ nonProfiled = scaleCodeHeapSize(nonProfiled);
+ nonNMethods = scaleCodeHeapSize(nonNMethods);
+ }
+
+ verifyHeapSizesSum(options.reserved, profiled, nonProfiled,
+ nonNMethods);
+ }
+
+ private static void verifyHeapSizesSum(long reserved, long profiled,
+ long nonProfiled, long nonNmethods) throws Throwable {
+ // JVM startup expected to fail when
+ // sum(all code heap sizes) != reserved CC size
+ CommandLineOptionTest.verifySameJVMStartup(
+ new String[]{ INCONSISTENT_CH_SIZES_ERROR },
+ /* unexpected messages */ null,
+ "JVM startup should fail with inconsistent code heap size.",
+ "JVM output should contain appropriate error message of code "
+ + "heap sizes are inconsistent",
+ ExitCode.FAIL,
+ CommandLineOptionTest.prepareBooleanFlag(
+ CodeCacheOptions.SEGMENTED_CODE_CACHE, true),
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.All.sizeOptionName, reserved),
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.MethodProfiled.sizeOptionName, profiled),
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.MethodNonProfiled.sizeOptionName, nonProfiled),
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.NonNMethod.sizeOptionName, nonNmethods));
+ }
+
+ /**
+ * Returns {@code unscaledSize} value scaled by a random factor from
+ * range (1, 2). If {@code unscaledSize} is not 0, then this
+ * method will return value that won't be equal to {@code unscaledSize}.
+ *
+ * @param unscaledSize The value to be scaled.
+ * @return {@code unscaledSize} value scaled by a factor from range (1, 2).
+ */
+ private static long scaleCodeHeapSize(long unscaledSize) {
+ Random random = Utils.getRandomInstance();
+
+ long scaledSize = unscaledSize;
+ while (scaledSize == unscaledSize && unscaledSize != 0) {
+ float scale = 1.0f + random.nextFloat();
+ scaledSize = (long) Math.ceil(scale * unscaledSize);
+ }
+ return scaledSize;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package codeheapsize;
+
+import com.oracle.java.testlibrary.Platform;
+import common.CodeCacheCLITestBase;
+import common.CodeCacheCLITestCase;
+import sun.hotspot.code.BlobType;
+import java.util.EnumSet;
+/**
+ * @test
+ * @bug 8015774
+ * @summary Verify processing of options related to code heaps sizing.
+ * @library /testlibrary .. /../../test/lib
+ * @build TestCodeHeapSizeOptions com.oracle.java.testlibrary.* codeheapsize.*
+ * common.*
+ * @run main/timeout=240 codeheapsize.TestCodeHeapSizeOptions
+ */
+public class TestCodeHeapSizeOptions extends CodeCacheCLITestBase {
+ private static final CodeCacheCLITestCase JVM_STARTUP
+ = new CodeCacheCLITestCase(new CodeCacheCLITestCase.Description(
+ options -> options.segmented,
+ EnumSet.noneOf(BlobType.class)),
+ new JVMStartupRunner());
+
+ private static final CodeCacheCLITestCase CODE_CACHE_FREE_SPACE
+ = new CodeCacheCLITestCase(new CodeCacheCLITestCase.Description(
+ options -> options.segmented
+ && Platform.isDebugBuild(),
+ EnumSet.noneOf(BlobType.class)),
+ new CodeCacheFreeSpaceRunner());
+
+ private static final GenericCodeHeapSizeRunner GENERIC_RUNNER
+ = new GenericCodeHeapSizeRunner();
+
+ private TestCodeHeapSizeOptions() {
+ super(CodeCacheCLITestBase.OPTIONS_SET,
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.INT_MODE.description,
+ GENERIC_RUNNER),
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.NON_TIERED.description,
+ GENERIC_RUNNER),
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.TIERED_LEVEL_0.description,
+ GENERIC_RUNNER),
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.TIERED_LEVEL_1.description,
+ GENERIC_RUNNER),
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.TIERED_LEVEL_4.description,
+ GENERIC_RUNNER),
+ JVM_STARTUP,
+ CODE_CACHE_FREE_SPACE);
+ }
+
+ public static void main(String args[]) throws Throwable {
+ new TestCodeHeapSizeOptions().runTestCases();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/common/CodeCacheCLITestBase.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common;
+
+/**
+ * Base for code cache related command line options tests.
+ */
+public class CodeCacheCLITestBase {
+ public static final CodeCacheOptions[] OPTIONS_SET
+ = new CodeCacheOptions[] {
+ new CodeCacheOptions(CodeCacheOptions.mB(60),
+ CodeCacheOptions.mB(20), CodeCacheOptions.mB(20),
+ CodeCacheOptions.mB(20)),
+ new CodeCacheOptions(CodeCacheOptions.mB(200),
+ CodeCacheOptions.mB(75), CodeCacheOptions.mB(75),
+ CodeCacheOptions.mB(50)),
+ new CodeCacheOptions(CodeCacheOptions.mB(300),
+ CodeCacheOptions.mB(100), CodeCacheOptions.mB(100),
+ CodeCacheOptions.mB(100)),
+ new CodeCacheOptions(CodeCacheOptions.mB(60)),
+ new CodeCacheOptions(CodeCacheOptions.mB(200)),
+ new CodeCacheOptions(CodeCacheOptions.mB(300))
+ };
+
+ private final CodeCacheCLITestCase[] testCases;
+ private final CodeCacheOptions[] options;
+
+ public CodeCacheCLITestBase(CodeCacheOptions[] options,
+ CodeCacheCLITestCase... testCases) {
+ this.testCases = testCases;
+ this.options = options;
+ }
+
+ protected void runTestCases() throws Throwable {
+ for (CodeCacheCLITestCase testCase : testCases) {
+ for (CodeCacheOptions opts : options) {
+ testCase.run(opts);
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/common/CodeCacheCLITestCase.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common;
+
+import com.oracle.java.testlibrary.Platform;
+import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
+import sun.hotspot.code.BlobType;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.function.Function;
+
+/**
+ * Code cache related command line option test case consisting of description
+ * of code heaps used during test case run and additional options that should
+ * be passed to JVM and runner aimed to perform actual testing based on the
+ * description.
+ */
+public class CodeCacheCLITestCase {
+ private static final Function<CodeCacheOptions, Boolean> ONLY_SEGMENTED
+ = options -> options.segmented;
+ private static final Function<CodeCacheOptions, Boolean> SEGMENTED_SERVER
+ = ONLY_SEGMENTED.andThen(isSegmented -> isSegmented
+ && Platform.isServer() && Platform.isTieredSupported());
+ private static final String USE_INT_MODE = "-Xint";
+ private static final String SEGMENTED_CODE_CACHE = "SegmentedCodeCache";
+ private static final String TIERED_COMPILATION = "TieredCompilation";
+ private static final String TIERED_STOP_AT = "TieredStopAtLevel";
+
+ private final Description description;
+ private final Runner runner;
+
+ public CodeCacheCLITestCase(Description description, Runner runner) {
+ this.description = description;
+ this.runner = runner;
+ }
+
+ public final void run(CodeCacheOptions options) throws Throwable {
+ if (description.isApplicable(options)) {
+ runner.run(description, options);
+ }
+ }
+
+ public enum CommonDescriptions {
+ /**
+ * Verifies that in interpreted mode PrintCodeCache output contains
+ * only NonNMethod code heap.
+ */
+ INT_MODE(ONLY_SEGMENTED, EnumSet.of(BlobType.NonNMethod), USE_INT_MODE),
+ /**
+ * Verifies that with disabled SegmentedCodeCache PrintCodeCache output
+ * contains only CodeCache's entry.
+ */
+ NON_SEGMENTED(options -> !options.segmented, EnumSet.of(BlobType.All),
+ CommandLineOptionTest.prepareBooleanFlag(SEGMENTED_CODE_CACHE,
+ false)),
+ /**
+ * Verifies that with disabled tiered compilation and enabled segmented
+ * code cache PrintCodeCache output does not contain information about
+ * profiled-nmethods heap and non-segmented CodeCache.
+ */
+ NON_TIERED(ONLY_SEGMENTED,
+ EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled),
+ CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION,
+ false)),
+ /**
+ * Verifies that with TieredStopAtLevel=0 PrintCodeCache output will
+ * contain information about non-nmethods and non-profiled nmethods
+ * heaps only.
+ */
+ TIERED_LEVEL_0(SEGMENTED_SERVER,
+ EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled),
+ CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION,
+ true),
+ CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 0)),
+ /**
+ * Verifies that with TieredStopAtLevel=1 PrintCodeCache output will
+ * contain information about non-nmethods and non-profiled nmethods
+ * heaps only.
+ */
+ TIERED_LEVEL_1(SEGMENTED_SERVER,
+ EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled),
+ CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION,
+ true),
+ CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 1)),
+ /**
+ * Verifies that with TieredStopAtLevel=4 PrintCodeCache output will
+ * contain information about all three code heaps.
+ */
+ TIERED_LEVEL_4(SEGMENTED_SERVER,
+ EnumSet.complementOf(EnumSet.of(BlobType.All)),
+ CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION,
+ true),
+ CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 4));
+
+ CommonDescriptions(Function<CodeCacheOptions, Boolean> predicate,
+ EnumSet<BlobType> involvedCodeHeaps,
+ String... additionalOptions) {
+ this.description = new Description(predicate,
+ involvedCodeHeaps, additionalOptions);
+ }
+
+
+ public final Description description;
+ }
+
+ public static class Description {
+ public final EnumSet<BlobType> involvedCodeHeaps;
+ private final String[] testCaseSpecificOptions;
+ private final Function<CodeCacheOptions, Boolean> predicate;
+
+ public Description(Function<CodeCacheOptions, Boolean> predicate,
+ EnumSet<BlobType> involvedCodeHeaps,
+ String... testCaseSpecificOptions) {
+ this.involvedCodeHeaps = involvedCodeHeaps;
+ this.testCaseSpecificOptions = testCaseSpecificOptions;
+ this.predicate = predicate;
+ }
+
+ public boolean isApplicable(CodeCacheOptions options) {
+ return predicate.apply(options);
+ }
+
+ public CodeCacheOptions expectedValues(CodeCacheOptions options) {
+ return options.mapOptions(involvedCodeHeaps);
+ }
+
+ public String[] getTestOptions(CodeCacheOptions codeCacheOptions,
+ String... additionalOptions) {
+ List<String> options = new LinkedList<>();
+ Collections.addAll(options, testCaseSpecificOptions);
+ Collections.addAll(options, additionalOptions);
+ return codeCacheOptions.prepareOptions(
+ options.toArray(new String[options.size()]));
+ }
+ }
+
+ public static interface Runner {
+ public void run(Description testCaseDescription,
+ CodeCacheOptions options) throws Throwable;
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/common/CodeCacheInfoFormatter.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common;
+
+import sun.hotspot.code.BlobType;
+import java.util.Arrays;
+
+public class CodeCacheInfoFormatter {
+ private static final String DEFAULT_SIZE_FORMAT = "[0-9]+Kb";
+ private BlobType heap = null;
+ private String size = DEFAULT_SIZE_FORMAT;
+ private String used = DEFAULT_SIZE_FORMAT;
+ private String maxUsed = DEFAULT_SIZE_FORMAT;
+ private String free = DEFAULT_SIZE_FORMAT;
+
+ public static CodeCacheInfoFormatter forHeap(BlobType heap) {
+ return new CodeCacheInfoFormatter(heap);
+ }
+
+ public static String[] forHeaps(BlobType... heaps) {
+ return Arrays.stream(heaps)
+ .map(CodeCacheInfoFormatter::forHeap)
+ .map(CodeCacheInfoFormatter::getInfoString)
+ .toArray(String[]::new);
+ }
+
+ private static String formatSize(long suffix) {
+ return String.format("%dKb", suffix / 1024);
+ }
+
+ private CodeCacheInfoFormatter(BlobType heap) {
+ this.heap = heap;
+ }
+
+ public CodeCacheInfoFormatter withSize(long size) {
+ this.size = CodeCacheInfoFormatter.formatSize(size);
+ return this;
+ }
+
+ public CodeCacheInfoFormatter withUsed(long used) {
+ this.used = CodeCacheInfoFormatter.formatSize(used);
+ return this;
+ }
+
+ public CodeCacheInfoFormatter withMaxUsed(long maxUsed) {
+ this.maxUsed = CodeCacheInfoFormatter.formatSize(maxUsed);
+ return this;
+ }
+
+ public CodeCacheInfoFormatter withFree(long free) {
+ this.free = CodeCacheInfoFormatter.formatSize(free);
+ return this;
+ }
+
+ public String getInfoString() {
+ return String.format("%s: size=%s used=%s max_used=%s free=%s",
+ heap.beanName, size, used, maxUsed, free);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/common/CodeCacheOptions.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package common;
+
+import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
+import sun.hotspot.code.BlobType;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+
+public class CodeCacheOptions {
+ public static final String SEGMENTED_CODE_CACHE = "SegmentedCodeCache";
+
+ private static final EnumSet<BlobType> NON_SEGMENTED_HEAPS
+ = EnumSet.of(BlobType.All);
+ private static final EnumSet<BlobType> ALL_SEGMENTED_HEAPS
+ = EnumSet.complementOf(NON_SEGMENTED_HEAPS);
+ private static final EnumSet<BlobType> SEGMENTED_HEAPS_WO_PROFILED
+ = EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled);
+ private static final EnumSet<BlobType> ONLY_NON_METHODS_HEAP
+ = EnumSet.of(BlobType.NonNMethod);
+
+ public final long reserved;
+ public final long nonNmethods;
+ public final long nonProfiled;
+ public final long profiled;
+ public final boolean segmented;
+
+ public static long mB(long val) {
+ return CodeCacheOptions.kB(val) * 1024L;
+ }
+
+ public static long kB(long val) {
+ return val * 1024L;
+ }
+
+ public CodeCacheOptions(long reserved) {
+ this.reserved = reserved;
+ this.nonNmethods = 0;
+ this.nonProfiled = 0;
+ this.profiled = 0;
+ this.segmented = false;
+ }
+
+ public CodeCacheOptions(long reserved, long nonNmethods, long nonProfiled,
+ long profiled) {
+ this.reserved = reserved;
+ this.nonNmethods = nonNmethods;
+ this.nonProfiled = nonProfiled;
+ this.profiled = profiled;
+ this.segmented = true;
+ }
+
+ public long sizeForHeap(BlobType heap) {
+ switch (heap) {
+ case All:
+ return this.reserved;
+ case NonNMethod:
+ return this.nonNmethods;
+ case MethodNonProfiled:
+ return this.nonProfiled;
+ case MethodProfiled:
+ return this.profiled;
+ default:
+ throw new Error("Unknown heap: " + heap.name());
+ }
+ }
+
+ public String[] prepareOptions(String... additionalOptions) {
+ List<String> options = new ArrayList<>();
+ Collections.addAll(options, additionalOptions);
+ Collections.addAll(options,
+ CommandLineOptionTest.prepareBooleanFlag(
+ SEGMENTED_CODE_CACHE, segmented),
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.All.sizeOptionName, reserved));
+
+ if (segmented) {
+ Collections.addAll(options,
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.NonNMethod.sizeOptionName, nonNmethods),
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.MethodNonProfiled.sizeOptionName,
+ nonProfiled),
+ CommandLineOptionTest.prepareNumericFlag(
+ BlobType.MethodProfiled.sizeOptionName, profiled));
+ }
+ return options.toArray(new String[options.size()]);
+ }
+
+ public CodeCacheOptions mapOptions(EnumSet<BlobType> involvedCodeHeaps) {
+ if (involvedCodeHeaps.isEmpty()
+ || involvedCodeHeaps.equals(NON_SEGMENTED_HEAPS)
+ || involvedCodeHeaps.equals(ALL_SEGMENTED_HEAPS)) {
+ return this;
+ } else if (involvedCodeHeaps.equals(SEGMENTED_HEAPS_WO_PROFILED)) {
+ return new CodeCacheOptions(reserved, nonNmethods,
+ profiled + nonProfiled, 0L);
+ } else if (involvedCodeHeaps.equals(ONLY_NON_METHODS_HEAP)) {
+ return new CodeCacheOptions(reserved, nonNmethods + profiled
+ + nonProfiled, 0L, 0L);
+ } else {
+ throw new Error("Test bug: unexpected set of code heaps involved "
+ + "into test.");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/printcodecache/PrintCodeCacheRunner.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package printcodecache;
+
+import com.oracle.java.testlibrary.ExitCode;
+import com.oracle.java.testlibrary.cli.CommandLineOptionTest;
+import common.CodeCacheCLITestCase;
+import common.CodeCacheInfoFormatter;
+import common.CodeCacheOptions;
+import sun.hotspot.code.BlobType;
+
+import java.util.EnumSet;
+import java.util.stream.Collectors;
+
+/**
+ * Runner implementation aimed to verify PrintCodeCache output.
+ */
+public class PrintCodeCacheRunner implements CodeCacheCLITestCase.Runner {
+ private final boolean printCodeCache;
+
+ public PrintCodeCacheRunner(boolean printCodeCache) {
+ this.printCodeCache = printCodeCache;
+ }
+
+ public PrintCodeCacheRunner() {
+ this(true);
+ }
+
+ @Override
+ public void run(CodeCacheCLITestCase.Description testCaseDescription,
+ CodeCacheOptions options) throws Throwable {
+ CodeCacheOptions expectedValues
+ = testCaseDescription.expectedValues(options);
+
+ String[] expectedMessages
+ = testCaseDescription.involvedCodeHeaps.stream()
+ .map(heap -> CodeCacheInfoFormatter.forHeap(heap)
+ .withSize(expectedValues.sizeForHeap(heap)))
+ .map(CodeCacheInfoFormatter::getInfoString)
+ .toArray(String[]::new);
+
+ EnumSet<BlobType> unexpectedHeapsSet
+ = EnumSet.complementOf(testCaseDescription.involvedCodeHeaps);
+
+ String[] unexpectedMessages = CodeCacheInfoFormatter.forHeaps(
+ unexpectedHeapsSet.toArray(
+ new BlobType[unexpectedHeapsSet.size()]));
+
+ String description = String.format("JVM output should contain entries "
+ + "for following code heaps: [%s] and should not contain "
+ + "entries for following code heaps: [%s].",
+ testCaseDescription.involvedCodeHeaps.stream()
+ .map(BlobType::name)
+ .collect(Collectors.joining(", ")),
+ unexpectedHeapsSet.stream()
+ .map(BlobType::name)
+ .collect(Collectors.joining(", ")));
+
+ CommandLineOptionTest.verifySameJVMStartup(expectedMessages,
+ unexpectedMessages, "JVM startup failure is not expected, "
+ + "since all options have allowed values", description,
+ ExitCode.OK,
+ testCaseDescription.getTestOptions(options,
+ CommandLineOptionTest.prepareBooleanFlag(
+ "PrintCodeCache", printCodeCache)));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package printcodecache;
+
+import common.CodeCacheCLITestBase;
+import common.CodeCacheCLITestCase;
+import sun.hotspot.code.BlobType;
+import java.util.EnumSet;
+/**
+ * @test
+ * @bug 8015774
+ * @summary Verify that PrintCodeCache option print correct information.
+ * @library /testlibrary .. /../../test/lib
+ * @build TestPrintCodeCacheOption com.oracle.java.testlibrary.*
+ * printcodecache.* common.*
+ * @run main/timeout=240 printcodecache.TestPrintCodeCacheOption
+ */
+public class TestPrintCodeCacheOption extends CodeCacheCLITestBase {
+ private static final CodeCacheCLITestCase DISABLED_PRINT_CODE_CACHE
+ = new CodeCacheCLITestCase(new CodeCacheCLITestCase.Description(
+ options -> true, EnumSet.noneOf(BlobType.class)),
+ new PrintCodeCacheRunner(false));
+
+ private static final CodeCacheCLITestCase.Runner DEFAULT_RUNNER
+ = new PrintCodeCacheRunner();
+
+ private TestPrintCodeCacheOption() {
+ super(CodeCacheCLITestBase.OPTIONS_SET,
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.INT_MODE.description,
+ DEFAULT_RUNNER),
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.NON_SEGMENTED.description,
+ DEFAULT_RUNNER),
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.NON_TIERED.description,
+ DEFAULT_RUNNER),
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.TIERED_LEVEL_0.description,
+ DEFAULT_RUNNER),
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.TIERED_LEVEL_1.description,
+ DEFAULT_RUNNER),
+ new CodeCacheCLITestCase(CodeCacheCLITestCase
+ .CommonDescriptions.TIERED_LEVEL_4.description,
+ DEFAULT_RUNNER),
+ DISABLED_PRINT_CODE_CACHE);
+ }
+
+ public static void main(String args[]) throws Throwable {
+ new TestPrintCodeCacheOption().runTestCases();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.Utils;
+import com.oracle.java.testlibrary.dtrace.DtraceResultsAnalyzer;
+import com.oracle.java.testlibrary.dtrace.DtraceRunner;
+import java.io.IOException;
+import java.lang.reflect.Executable;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/*
+ * @test SegmentedCodeCacheDtraceTest
+ * @bug 8015774
+ * @requires os.family=="solaris"
+ * @library /testlibrary /compiler/testlibrary /../../test/lib
+ * @build SegmentedCodeCacheDtraceTestWorker
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+TieredCompilation
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * SegmentedCodeCacheDtraceTest
+ * @summary testing of dtrace for segmented code cache
+ */
+public class SegmentedCodeCacheDtraceTest {
+
+ private static final String WORKER_CLASS_NAME
+ = SegmentedCodeCacheDtraceTestWorker.class.getName();
+ private static final String JAVA_OPTS = " -XX:+DTraceMethodProbes "
+ + "-Xbootclasspath/a:" + System.getProperty("test.classes") + " "
+ + "-XX:+UnlockDiagnosticVMOptions "
+ + "-XX:+WhiteBoxAPI -XX:+SegmentedCodeCache "
+ + "-XX:CompileCommand=compileonly,"
+ + WORKER_CLASS_NAME + "::* "
+ + " -classpath " + System.getProperty("test.class.path") + " "
+ + String.join(" ", Utils.getTestJavaOpts());
+ private static final String DTRACE_SCRIPT
+ = "SegmentedCodeCacheDtraceTestScript.d";
+ private static final List<Executable> MLIST =
+ SegmentedCodeCacheDtraceTestWorker.TESTED_METHODS_LIST;
+ private static final int WORKER_METHODS_COUNT = MLIST.size();
+
+ private void runTest(TestCombination tc) {
+ String params = MLIST.stream()
+ .map(Executable::getName)
+ .map(x -> tc.data.get(x).compileLevel + " " + tc.data.get(x).isInlined)
+ .collect(Collectors.joining(" "));
+ DtraceRunner runner = new DtraceRunner();
+ runner.runDtrace(JDKToolFinder.getTestJDKTool("java"), JAVA_OPTS,
+ WORKER_CLASS_NAME, params, Paths.get(System.getProperty("test.src"),
+ DTRACE_SCRIPT).toString(),
+ DtraceRunner.PERMIT_DESTRUCTIVE_ACTIONS_DTRACE_OPTION,
+ new SegmentedCodeCacheDtraceResultsAnalyzer());
+ }
+
+ private static TestCombination generateUniqueCombination(
+ int[] availableLevels, Set<TestCombination> combinations) {
+ int len = availableLevels.length;
+ /* first, check if we're out of combinations. */
+ int maxCombinationsCount
+ = (1 << WORKER_METHODS_COUNT)
+ * (int) Math.pow(len, WORKER_METHODS_COUNT);
+ if (combinations.size() == maxCombinationsCount) {
+ return null;
+ }
+ Random r = Utils.getRandomInstance();
+ while (combinations.size() < maxCombinationsCount) {
+ int levels[] = new int[WORKER_METHODS_COUNT];
+ boolean inlines[] = new boolean[WORKER_METHODS_COUNT];
+ for (int i = 0; i < WORKER_METHODS_COUNT; i++) {
+ levels[i] = availableLevels[r.nextInt(len)];
+ inlines[i] = r.nextBoolean();
+ }
+ TestCombination tc = new TestCombination(levels, inlines);
+ if (combinations.add(tc)) {
+ return tc;
+ }
+ }
+ return null;
+ }
+
+ public static void main(String args[]) {
+ int iterations
+ = Integer.getInteger("com.oracle.java.testlibrary.iterations", 1);
+ if (!DtraceRunner.dtraceAvailable()) {
+ System.out.println("INFO: There is no dtrace avaiable. Skipping.");
+ return;
+ }
+ int[] availableLevels = CompilerUtils.getAvailableCompilationLevels();
+ // adding one more entry(zero) for interpeter
+ availableLevels
+ = Arrays.copyOf(availableLevels, availableLevels.length + 1);
+ Set<TestCombination> combinations = new HashSet<>();
+ for (int i = 0; i < iterations; i++) {
+ TestCombination tc
+ = generateUniqueCombination(availableLevels, combinations);
+ if (tc == null) {
+ System.out.println("INFO: no more combinations available");
+ return;
+ } else {
+ System.out.println("INFO: Running testcase for: " + tc);
+ new SegmentedCodeCacheDtraceTest().runTest(tc);
+ }
+ }
+ }
+
+ private static class MethodData {
+
+ public final int compileLevel;
+ public final boolean isInlined;
+ public final String name;
+
+ public MethodData(String name, int compileLevel, boolean isInlined) {
+ this.name = name;
+ this.compileLevel = compileLevel;
+ this.isInlined = isInlined;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || !(o instanceof MethodData)) {
+ return false;
+ }
+ MethodData md = (MethodData) o;
+ return md.compileLevel == compileLevel
+ && md.isInlined == isInlined
+ && md.name.equals(name);
+ }
+
+ @Override
+ public int hashCode() {
+ return 100 * name.hashCode() + 10 * compileLevel + (isInlined ? 1 : 0);
+ }
+
+ @Override
+ public String toString() {
+ return name + " " + compileLevel + " " + isInlined;
+ }
+ }
+
+ private static class TestCombination {
+
+ private final Map<String, MethodData> data;
+
+ public TestCombination(int compLevels[], boolean inlines[]) {
+ Map<String, MethodData> d = new HashMap<>();
+ for (int i = 0; i < MLIST.size(); i++) {
+ d.put(MLIST.get(i).getName(), new MethodData(MLIST.get(i).getName(),
+ compLevels[i], inlines[i]));
+ }
+ data = Collections.unmodifiableMap(d);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || !(o instanceof TestCombination)) {
+ return false;
+ }
+ TestCombination second = (TestCombination) o;
+ return second.data.equals(data);
+ }
+
+ @Override
+ public int hashCode() {
+ int sum = 0;
+ for (MethodData md : data.values()) {
+ sum += md.hashCode();
+ }
+ return sum;
+ }
+
+ private String getMethodDescString(MethodData md) {
+ return (md == null)
+ ? null
+ : String.format("Method %s compilation level %d and %s",
+ md.name, md.compileLevel,
+ md.isInlined ? "inlined" : "not inlined");
+ }
+
+ @Override
+ public String toString() {
+ return data.values().stream().map(m -> getMethodDescString(m))
+ .collect(Collectors.joining(Utils.NEW_LINE,
+ "Combination: ", ""));
+ }
+ }
+
+ private class SegmentedCodeCacheDtraceResultsAnalyzer
+ implements DtraceResultsAnalyzer {
+
+ private static final int EXPECTED_MATCH_COUNT = 2;
+
+ private final Pattern checkPattern;
+
+ public SegmentedCodeCacheDtraceResultsAnalyzer() {
+ String workerClassRegExp = "\\s*" + WORKER_CLASS_NAME + "\\.";
+ String delimeter = "\\(\\)V\\*?" + workerClassRegExp;
+ String suffix = "test\\(\\)V\\*?" + workerClassRegExp
+ + "main\\(\\[Ljava\\/lang\\/String;\\)V";
+ StringBuilder sb = new StringBuilder(workerClassRegExp);
+ // method order is important, so, going from list tail to head,
+ // accoring to call order representation in stacktrace
+ for (int i = MLIST.size() - 1; i > -1; i--) {
+ sb.append(MLIST.get(i).getName()).append(delimeter);
+ }
+ sb.append(suffix);
+ checkPattern = Pattern.compile(sb.toString());
+ /* such pattern match should pass on a stacktrace like
+ CPU ID FUNCTION:NAME
+ 0 53573 __1cNSharedRuntimeTdtrace_method_entry6FpnKJavaThread_pnGMethod__i_:method-entry ustack:
+
+ libjvm.so`__1cNSharedRuntimeTdtrace_method_entry6FpnKJavaThread_pnGMethod__i_+0x39c
+ SegmentedCodeCacheDtraceTestWorker.baz()V*
+ SegmentedCodeCacheDtraceTestWorker.bar()V
+ SegmentedCodeCacheDtraceTestWorker.foo()V*
+ SegmentedCodeCacheDtraceTestWorker.test()V
+ SegmentedCodeCacheDtraceTestWorker.main([Ljava/lang/String;)V
+ 0xffffffff6b0004b8
+ libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_+0x94c
+ libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_pnI_jobject_nLJNICallType_pnK_jmethodID_pnSJNI_ArgumentPusher_pnGThread__v_+0xa64
+ libjvm.so`jni_CallStaticVoidMethod+0x508
+ libjli.so`JavaMain+0x584
+ libc.so.1`_lwp_start
+ jstack:
+
+ libjvm.so`__1cNSharedRuntimeTdtrace_method_entry6FpnKJavaThread_pnGMethod__i_+0x39c
+ SegmentedCodeCacheDtraceTestWorker.baz()V*
+ SegmentedCodeCacheDtraceTestWorker.bar()V
+ SegmentedCodeCacheDtraceTestWorker.foo()V*
+ SegmentedCodeCacheDtraceTestWorker.test()V
+ SegmentedCodeCacheDtraceTestWorker.main([Ljava/lang/String;)V
+ 0xffffffff6b0004b8
+ libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_+0x94c
+ libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_pnI_jobject_nLJNICallType_pnK_jmethodID_pnSJNI_ArgumentPusher_pnGThread__v_+0xa64
+ libjvm.so`jni_CallStaticVoidMethod+0x508
+ libjli.so`JavaMain+0x584
+ libc.so.1`_lwp_start
+ */
+ }
+
+ protected List<String> loadLog(String dtraceOutFile) throws IOException {
+ return Files.readAllLines(Paths.get(dtraceOutFile));
+ }
+
+ @Override
+ public void analyze(OutputAnalyzer oa, String dtraceOutFilePath) {
+ oa.shouldHaveExitValue(0);
+ List<String> dOut;
+ try {
+ dOut = loadLog(dtraceOutFilePath);
+ } catch (IOException e) {
+ throw new Error("Can't load log", e);
+ }
+ StringBuilder allDtraceOutput = new StringBuilder();
+ for (String entry : dOut) {
+ allDtraceOutput.append(entry);
+ }
+ int matchCount = getMatchCount(allDtraceOutput.toString());
+ Asserts.assertEQ(matchCount, EXPECTED_MATCH_COUNT,
+ "Unexpected output match amount. expected: "
+ + EXPECTED_MATCH_COUNT + " but found " + matchCount);
+ }
+
+ protected int getMatchCount(String source) {
+ Matcher m = checkPattern.matcher(source);
+ int matchCount = 0;
+ while (m.find()) {
+ matchCount++;
+ }
+ return matchCount;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTestScript.d Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,33 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+
+ This code is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License version 2 only, as
+ published by the Free Software Foundation.
+
+ This code is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ version 2 for more details (a copy is included in the LICENSE file that
+ accompanied this code).
+
+ You should have received a copy of the GNU General Public License version
+ 2 along with this work; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ or visit www.oracle.com if you need additional information or have any
+ questions.
+*/
+
+hotspot$target:::method-entry
+/ copyinstr(arg3, arg4) == "baz" /
+{
+ printf("ustack:\n");
+ ustack(50, 500);
+ printf("jstack:\n");
+ jstack();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTestWorker.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Utils;
+import java.lang.reflect.Executable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import sun.hotspot.WhiteBox;
+
+public class SegmentedCodeCacheDtraceTestWorker {
+
+ private static final String METHOD1_NAME = "foo";
+ private static final String METHOD2_NAME = "bar";
+ private static final String METHOD3_NAME = "baz";
+ public static final List<Executable> TESTED_METHODS_LIST;
+ private final WhiteBox wb;
+ private final int compLevels[];
+
+ static {
+ List<Executable> methods = new ArrayList<>();
+ try {
+ // method order is important. Need to place methods in call order,
+ // to be able to verify results later
+ methods.add(SegmentedCodeCacheDtraceTestWorker.class.getMethod(METHOD1_NAME));
+ methods.add(SegmentedCodeCacheDtraceTestWorker.class.getMethod(METHOD2_NAME));
+ methods.add(SegmentedCodeCacheDtraceTestWorker.class.getMethod(METHOD3_NAME));
+ } catch (NoSuchMethodException e) {
+ throw new Error("TESTBUG: no expected method found", e);
+ }
+ TESTED_METHODS_LIST = Collections.unmodifiableList(methods);
+ }
+
+ protected static final boolean BACKGROUND_COMPILATION
+ = WhiteBox.getWhiteBox().getBooleanVMFlag("BackgroundCompilation");
+
+ public static void main(String[] args) {
+ if (args.length != 2 * TESTED_METHODS_LIST.size()) {
+ throw new Error("Usage: java <thisClass> <fooCompLevel> <fooInlined>"
+ + "<barCompLevel> <barInlined> "
+ + "<bazCompLevel> <bazInlined>");
+ } else {
+ int compLevels[] = new int[TESTED_METHODS_LIST.size()];
+ boolean inlines[] = new boolean[TESTED_METHODS_LIST.size()];
+ for (int i = 0; i < TESTED_METHODS_LIST.size(); i++) {
+ compLevels[i] = Integer.parseInt(args[2 * i]);
+ inlines[i] = Boolean.parseBoolean(args[2 * i + 1]);
+ }
+ new SegmentedCodeCacheDtraceTestWorker(compLevels, inlines).test();
+ }
+ }
+
+ public SegmentedCodeCacheDtraceTestWorker(int compLevels[], boolean inlines[]) {
+ wb = WhiteBox.getWhiteBox();
+ this.compLevels = Arrays.copyOf(compLevels, compLevels.length);
+ for (int i = 0; i < compLevels.length; i++) {
+ if (inlines[i]) {
+ wb.testSetForceInlineMethod(TESTED_METHODS_LIST.get(i), true);
+ } else {
+ wb.testSetDontInlineMethod(TESTED_METHODS_LIST.get(i), true);
+ }
+ }
+ }
+
+ private void waitForCompilation(Executable executable, int compLevel) {
+ if (compLevel > 0) {
+ Utils.waitForCondition(() -> wb.isMethodCompiled(executable));
+ }
+ }
+
+ protected void test() {
+ for (int i = 0; i < TESTED_METHODS_LIST.size(); i++) {
+ Executable method = TESTED_METHODS_LIST.get(i);
+ int compLevel = compLevels[i];
+ wb.enqueueMethodForCompilation(method, compLevel);
+ waitForCompilation(method, compLevel);
+ }
+ foo();
+ }
+
+ public static void foo() {
+ bar();
+ }
+
+ public static void bar() {
+ baz();
+ }
+
+ public static void baz() {
+ System.out.println("Reached baz method");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/BeanTypeTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import java.lang.management.MemoryType;
+import sun.hotspot.code.BlobType;
+
+/**
+ * @test BeanTypeTest
+ * @library /testlibrary /../../test/lib
+ * @build BeanTypeTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache BeanTypeTest
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache BeanTypeTest
+ * @summary verify types of code cache memory pool bean
+ */
+public class BeanTypeTest {
+
+ public static void main(String args[]) {
+ for (BlobType bt : BlobType.getAvailable()) {
+ Asserts.assertEQ(MemoryType.NON_HEAP, bt.getMemoryPool().getType());
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/CodeCacheUtils.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Utils;
+import java.lang.management.MemoryPoolMXBean;
+import javax.management.Notification;
+import sun.hotspot.WhiteBox;
+import sun.hotspot.code.BlobType;
+import sun.hotspot.code.CodeBlob;
+
+public final class CodeCacheUtils {
+
+ /**
+ * Returns the value to be used for code heap allocation
+ */
+ public static final int ALLOCATION_SIZE
+ = Integer.getInteger("codecache.allocation.size", 100);
+ public static final WhiteBox WB = WhiteBox.getWhiteBox();
+ public static final long SEGMENT_SIZE
+ = WhiteBox.getWhiteBox().getUintxVMFlag("CodeCacheSegmentSize");
+ public static final long MIN_BLOCK_LENGTH
+ = WhiteBox.getWhiteBox().getUintxVMFlag("CodeCacheMinBlockLength");
+ public static final long MIN_ALLOCATION = SEGMENT_SIZE * MIN_BLOCK_LENGTH;
+
+ private CodeCacheUtils() {
+ // To prevent from instantiation
+ }
+
+ public static final void hitUsageThreshold(MemoryPoolMXBean bean,
+ BlobType btype) {
+ long initialSize = bean.getUsage().getUsed();
+ bean.setUsageThreshold(initialSize + 1);
+ long usageThresholdCount = bean.getUsageThresholdCount();
+ long addr = WB.allocateCodeBlob(1, btype.id);
+ WB.fullGC();
+ Utils.waitForCondition(()
+ -> bean.getUsageThresholdCount() == usageThresholdCount + 1);
+ WB.freeCodeBlob(addr);
+ }
+
+ public static final long getHeaderSize(BlobType btype) {
+ long addr = WB.allocateCodeBlob(0, btype.id);
+ int size = CodeBlob.getCodeBlob(addr).size;
+ WB.freeCodeBlob(addr);
+ return size;
+ }
+
+ public static String getPoolNameFromNotification(
+ Notification notification) {
+ return ((javax.management.openmbean.CompositeDataSupport)
+ notification.getUserData()).get("poolName").toString();
+ }
+
+ public static boolean isAvailableCodeHeapPoolName(String name) {
+ return BlobType.getAvailable().stream()
+ .map(BlobType::getMemoryPool)
+ .map(MemoryPoolMXBean::getName)
+ .filter(name::equals)
+ .findAny().isPresent();
+ }
+
+ /**
+ * A "non-nmethods" code heap is used by interpreter during bytecode
+ * execution, thus, it can't be predicted if this code heap usage will be
+ * increased or not. Same goes for 'All'.
+ *
+ * @param btype BlobType to be checked
+ * @return boolean value, true if respective code heap is predictable
+ */
+ public static boolean isCodeHeapPredictable(BlobType btype) {
+ return btype == BlobType.MethodNonProfiled
+ || btype == BlobType.MethodProfiled;
+ }
+
+ public static void disableCollectionUsageThresholds(){
+ BlobType.getAvailable().stream()
+ .map(BlobType::getMemoryPool)
+ .filter(MemoryPoolMXBean::isCollectionUsageThresholdSupported)
+ .forEach(b -> b.setCollectionUsageThreshold(0L));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/CodeHeapBeanPresenceTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import java.util.EnumSet;
+import sun.hotspot.code.BlobType;
+
+/**
+ * @test CodeHeapBeanPresenceTest
+ * @library /testlibrary /../../test/lib
+ * @build CodeHeapBeanPresenceTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache CodeHeapBeanPresenceTest
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache CodeHeapBeanPresenceTest
+ * @summary verify CodeHeap bean presence
+ */
+public class CodeHeapBeanPresenceTest {
+
+ public static void main(String args[]) {
+ EnumSet<BlobType> shouldBeAvailable = BlobType.getAvailable();
+ EnumSet<BlobType> shouldNotBeAvailable
+ = EnumSet.complementOf(shouldBeAvailable);
+ for (BlobType btype : shouldBeAvailable) {
+ Asserts.assertNotNull(btype.getMemoryPool(),
+ "Can't find memory pool for " + btype.name());
+ }
+ for (BlobType btype : shouldNotBeAvailable) {
+ Asserts.assertNull(btype.getMemoryPool(),
+ "Memory pool unexpected for " + btype.name());
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/GetUsageTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import java.lang.management.MemoryPoolMXBean;
+import java.util.HashMap;
+import java.util.Map;
+import sun.hotspot.code.BlobType;
+
+/*
+ * @test GetUsageTest
+ * @library /testlibrary /../../test/lib
+ * @build GetUsageTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:CompileCommand=compileonly,null::*
+ * -XX:-UseCodeCacheFlushing -XX:-MethodFlushing -XX:+SegmentedCodeCache
+ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI GetUsageTest
+ * @summary testing of getUsage() for segmented code cache
+ */
+public class GetUsageTest {
+
+ private final BlobType btype;
+ private final int allocateSize;
+
+ public GetUsageTest(BlobType btype, int allocSize) {
+ this.btype = btype;
+ this.allocateSize = allocSize;
+ }
+
+ public static void main(String[] args) throws Exception {
+ for (BlobType btype : BlobType.getAvailable()) {
+ if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
+ for (int allocSize = 10; allocSize < 100000; allocSize *= 10) {
+ new GetUsageTest(btype, allocSize).runTest();
+ }
+ }
+ }
+ }
+
+ protected final Map<MemoryPoolMXBean, Long> getBeanUsages() {
+ Map<MemoryPoolMXBean, Long> beanUsages = new HashMap<>();
+ for (BlobType bt : BlobType.getAvailable()) {
+ beanUsages.put(bt.getMemoryPool(),
+ bt.getMemoryPool().getUsage().getUsed());
+ }
+ return beanUsages;
+ }
+
+ protected void runTest() {
+ MemoryPoolMXBean[] predictableBeans = BlobType.getAvailable().stream()
+ .filter(CodeCacheUtils::isCodeHeapPredictable)
+ .map(BlobType::getMemoryPool)
+ .toArray(MemoryPoolMXBean[]::new);
+ Map<MemoryPoolMXBean, Long> initial = getBeanUsages();
+ long addr = 0;
+ try {
+ addr = CodeCacheUtils.WB.allocateCodeBlob(allocateSize, btype.id);
+ Map<MemoryPoolMXBean, Long> current = getBeanUsages();
+ long blockCount = Math.floorDiv(allocateSize
+ + CodeCacheUtils.getHeaderSize(btype)
+ + CodeCacheUtils.SEGMENT_SIZE - 1, CodeCacheUtils.SEGMENT_SIZE);
+ long usageUpperEstimate = Math.max(blockCount,
+ CodeCacheUtils.MIN_BLOCK_LENGTH) * CodeCacheUtils.SEGMENT_SIZE;
+ for (MemoryPoolMXBean entry : predictableBeans) {
+ long diff = current.get(entry) - initial.get(entry);
+ if (entry.equals(btype.getMemoryPool())) {
+ Asserts.assertFalse(diff <= 0L || diff > usageUpperEstimate,
+ String.format("Pool %s usage increase was reported "
+ + "unexpectedly as increased by %d using "
+ + "allocation size %d", entry.getName(),
+ diff, allocateSize));
+ } else {
+ Asserts.assertEQ(diff, 0L,
+ String.format("Pool %s usage changed unexpectedly while"
+ + " trying to increase: %s using allocation "
+ + "size %d", entry.getName(),
+ btype.getMemoryPool().getName(), allocateSize));
+ }
+ }
+ } finally {
+ if (addr != 0) {
+ CodeCacheUtils.WB.freeCodeBlob(addr);
+ }
+ }
+ System.out.printf("INFO: Scenario finished successfully for %s%n",
+ btype.getMemoryPool().getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/InitialAndMaxUsageTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import java.lang.management.MemoryPoolMXBean;
+import java.util.ArrayList;
+import java.util.List;
+import sun.hotspot.code.BlobType;
+
+/*
+ * @test InitialAndMaxUsageTest
+ * @library /testlibrary /../../test/lib
+ * @build InitialAndMaxUsageTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing
+ * -XX:-MethodFlushing -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -XX:+SegmentedCodeCache -XX:CompileCommand=compileonly,null::*
+ * InitialAndMaxUsageTest
+ * @summary testing of initial and max usage
+ */
+public class InitialAndMaxUsageTest {
+
+ private static final double CACHE_USAGE_COEF = 0.95d;
+ private final BlobType btype;
+ private final boolean lowerBoundIsZero;
+ private final long maxSize;
+
+ public InitialAndMaxUsageTest(BlobType btype) {
+ this.btype = btype;
+ this.maxSize = btype.getSize();
+ /* Only profiled code cache initial size should be 0, because of
+ -XX:CompileCommand=compileonly,null::* non-methods might be not empty,
+ as well as non-profiled methods, because it's used as fallback in
+ case non-methods is full */
+ lowerBoundIsZero = btype == BlobType.MethodProfiled;
+ }
+
+ public static void main(String[] args) {
+ for (BlobType btype : BlobType.getAvailable()) {
+ new InitialAndMaxUsageTest(btype).runTest();
+ }
+ }
+
+ private void fillWithSize(long size, List<Long> blobs) {
+ long blob;
+ while ((blob = CodeCacheUtils.WB.allocateCodeBlob(size, btype.id))
+ != 0L) {
+ blobs.add(blob);
+ }
+ }
+
+ protected void runTest() {
+ long headerSize = CodeCacheUtils.getHeaderSize(btype);
+ MemoryPoolMXBean bean = btype.getMemoryPool();
+ long initialUsage = btype.getMemoryPool().getUsage().getUsed();
+ System.out.printf("INFO: trying to test %s of max size %d and initial"
+ + " usage %d%n", bean.getName(), maxSize, initialUsage);
+ Asserts.assertLT(initialUsage + headerSize + 1L, maxSize,
+ "Initial usage is close to total size for " + bean.getName());
+ if (lowerBoundIsZero) {
+ Asserts.assertEQ(initialUsage, 0L, "Unexpected initial usage");
+ }
+ ArrayList<Long> blobs = new ArrayList<>();
+ long minAllocationUnit = CodeCacheUtils.MIN_ALLOCATION - headerSize;
+ /* now filling code cache with large-sized allocation first, since
+ lots of small allocations takes too much time, so, just a small
+ optimization */
+ try {
+ for (int coef = 1000000; coef > 0; coef /= 10) {
+ fillWithSize(coef * minAllocationUnit, blobs);
+ }
+ Asserts.assertGT((double) bean.getUsage().getUsed(),
+ CACHE_USAGE_COEF * maxSize, String.format("Unable to fill "
+ + "more than %f of %s. Reported usage is %d ",
+ CACHE_USAGE_COEF, bean.getName(),
+ bean.getUsage().getUsed()));
+ } finally {
+ for (long entry : blobs) {
+ CodeCacheUtils.WB.freeCodeBlob(entry);
+ }
+ }
+ System.out.printf("INFO: Scenario finished successfully for %s%n",
+ bean.getName());
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/ManagerNamesTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import java.lang.management.MemoryPoolMXBean;
+import sun.hotspot.code.BlobType;
+
+/**
+ * @test ManagerNamesTest
+ * @library /testlibrary /../../test/lib
+ * @build ManagerNamesTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache ManagerNamesTest
+ * * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache ManagerNamesTest
+ * @summary verify getMemoryManageNames calls in case of segmented code cache
+ */
+public class ManagerNamesTest {
+
+ private final MemoryPoolMXBean bean;
+ private final static String POOL_NAME = "CodeCacheManager";
+
+ public static void main(String args[]) {
+ for (BlobType btype : BlobType.getAvailable()) {
+ new ManagerNamesTest(btype).runTest();
+ }
+ }
+
+ public ManagerNamesTest(BlobType btype) {
+ bean = btype.getMemoryPool();
+ }
+
+ protected void runTest() {
+ String[] names = bean.getMemoryManagerNames();
+ Asserts.assertEQ(names.length, 1,
+ "Unexpected length of MemoryManagerNames");
+ Asserts.assertEQ(POOL_NAME, names[0],
+ "Unexpected value of MemoryManagerName");
+ System.out.printf("INFO: Scenario finished successfully for %s%n",
+ bean.getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/MemoryPoolsPresenceTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryManagerMXBean;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import sun.hotspot.code.BlobType;
+
+/**
+ * @test MemoryPoolsPresenceTest
+ * @library /testlibrary /../../test/lib
+ * @build MemoryPoolsPresenceTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache MemoryPoolsPresenceTest
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache MemoryPoolsPresenceTest
+ * @summary verify that MemoryManagerMXBean exists for every code cache segment
+ */
+public class MemoryPoolsPresenceTest {
+
+ private static final String CC_MANAGER = "CodeCacheManager";
+ private final Map<String, Integer> counters = new HashMap<>();
+
+ public static void main(String args[]) {
+ new MemoryPoolsPresenceTest().runTest();
+ }
+
+ protected void runTest() {
+ List<MemoryManagerMXBean> beans
+ = ManagementFactory.getMemoryManagerMXBeans();
+ Optional<MemoryManagerMXBean> any = beans
+ .stream()
+ .filter(bean -> CC_MANAGER.equals(bean.getName()))
+ .findAny();
+ Asserts.assertTrue(any.isPresent(), "Bean not found: " + CC_MANAGER);
+ MemoryManagerMXBean ccManager = any.get();
+ Asserts.assertNotNull(ccManager, "Found null for " + CC_MANAGER);
+ String names[] = ccManager.getMemoryPoolNames();
+ for (String name : names) {
+ counters.put(name, counters.containsKey(name)
+ ? counters.get(name) + 1 : 1);
+ }
+ for (BlobType btype : BlobType.getAvailable()) {
+ Asserts.assertEQ(counters.get(btype.getMemoryPool().getName()), 1,
+ "Found unexpected amount of beans for pool "
+ + btype.getMemoryPool().getName());
+ }
+ Asserts.assertEQ(BlobType.getAvailable().size(),
+ counters.keySet().size(), "Unexpected amount of bean names");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/PeakUsageTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import java.lang.management.MemoryPoolMXBean;
+import sun.hotspot.code.BlobType;
+
+/*
+ * @test PeakUsageTest
+ * @library /testlibrary /../../test/lib
+ * @build PeakUsageTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache
+ * -XX:CompileCommand=compileonly,null::* PeakUsageTest
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache
+ * -XX:CompileCommand=compileonly,null::* PeakUsageTest
+ * @summary testing of getPeakUsage() and resetPeakUsage for
+ * segmented code cache
+ */
+public class PeakUsageTest {
+
+ private final BlobType btype;
+
+ public PeakUsageTest(BlobType btype) {
+ this.btype = btype;
+ }
+
+ public static void main(String[] args) {
+ for (BlobType btype : BlobType.getAvailable()) {
+ if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
+ new PeakUsageTest(btype).runTest();
+ }
+ }
+ }
+
+ protected void runTest() {
+ MemoryPoolMXBean bean = btype.getMemoryPool();
+ bean.resetPeakUsage();
+ long addr = CodeCacheUtils.WB.allocateCodeBlob(
+ CodeCacheUtils.ALLOCATION_SIZE, btype.id);
+ long newPeakUsage = bean.getPeakUsage().getUsed();
+ try {
+ Asserts.assertEQ(newPeakUsage, bean.getUsage().getUsed(),
+ "Peak usage does not match usage after allocation for "
+ + bean.getName());
+ } finally {
+ if (addr != 0) {
+ CodeCacheUtils.WB.freeCodeBlob(addr);
+ }
+ }
+ Asserts.assertEQ(newPeakUsage, bean.getPeakUsage().getUsed(),
+ "Code cache peak usage has changed after usage decreased for "
+ + bean.getName());
+ bean.resetPeakUsage();
+ Asserts.assertEQ(bean.getPeakUsage().getUsed(),
+ bean.getUsage().getUsed(),
+ "Code cache peak usage is not equal to usage after reset for "
+ + bean.getName());
+ long addr2 = CodeCacheUtils.WB.allocateCodeBlob(
+ CodeCacheUtils.ALLOCATION_SIZE, btype.id);
+ try {
+ Asserts.assertEQ(bean.getPeakUsage().getUsed(),
+ bean.getUsage().getUsed(),
+ "Code cache peak usage is not equal to usage after fresh "
+ + "allocation for " + bean.getName());
+ } finally {
+ if (addr2 != 0) {
+ CodeCacheUtils.WB.freeCodeBlob(addr2);
+ }
+ }
+ System.out.printf("INFO: Scenario finished successfully for %s%n",
+ bean.getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/PoolsIndependenceTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.Utils;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryNotificationInfo;
+import java.lang.management.MemoryPoolMXBean;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.management.ListenerNotFoundException;
+import javax.management.Notification;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationListener;
+import sun.hotspot.code.BlobType;
+
+/*
+ * @test PoolsIndependenceTest
+ * @library /testlibrary /../../test/lib
+ * @build PoolsIndependenceTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing
+ * -XX:-MethodFlushing -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -XX:+SegmentedCodeCache PoolsIndependenceTest
+ * @summary testing of getUsageThreshold()
+ */
+public class PoolsIndependenceTest implements NotificationListener {
+
+ private final Map<String, AtomicInteger> counters;
+ private final BlobType btype;
+ private volatile long lastEventTimestamp;
+
+ public PoolsIndependenceTest(BlobType btype) {
+ counters = new HashMap<>();
+ for (BlobType bt : BlobType.getAvailable()) {
+ counters.put(bt.getMemoryPool().getName(), new AtomicInteger(0));
+ }
+ this.btype = btype;
+ lastEventTimestamp = 0;
+ CodeCacheUtils.disableCollectionUsageThresholds();
+ }
+
+ public static void main(String[] args) {
+ for (BlobType bt : BlobType.getAvailable()) {
+ new PoolsIndependenceTest(bt).runTest();
+ }
+ }
+
+ protected void runTest() {
+ MemoryPoolMXBean bean = btype.getMemoryPool();
+ ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
+ addNotificationListener(this, null, null);
+ bean.setUsageThreshold(bean.getUsage().getUsed() + 1);
+ long beginTimestamp = System.currentTimeMillis();
+ CodeCacheUtils.WB.allocateCodeBlob(
+ CodeCacheUtils.ALLOCATION_SIZE, btype.id);
+ CodeCacheUtils.WB.fullGC();
+ /* waiting for expected event to be received plus double the time took
+ to receive expected event(for possible unexpected) and
+ plus 1 second in case expected event received (almost)immediately */
+ Utils.waitForCondition(() -> {
+ long currentTimestamp = System.currentTimeMillis();
+ int eventsCount
+ = counters.get(btype.getMemoryPool().getName()).get();
+ if (eventsCount > 0) {
+ if (eventsCount > 1) {
+ return true;
+ }
+ long timeLastEventTook
+ = beginTimestamp - lastEventTimestamp;
+ long timeoutValue
+ = 1000L + beginTimestamp + 3L * timeLastEventTook;
+ return currentTimestamp > timeoutValue;
+ }
+ return false;
+ });
+ for (BlobType bt : BlobType.getAvailable()) {
+ int expectedNotificationsAmount = bt.equals(btype) ? 1 : 0;
+ Asserts.assertEQ(counters.get(bt.getMemoryPool().getName()).get(),
+ expectedNotificationsAmount, String.format("Unexpected "
+ + "amount of notifications for pool: %s",
+ bt.getMemoryPool().getName()));
+ }
+ try {
+ ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
+ removeNotificationListener(this);
+ } catch (ListenerNotFoundException ex) {
+ throw new AssertionError("Can't remove notification listener", ex);
+ }
+ System.out.printf("INFO: Scenario with %s finished%n", bean.getName());
+ }
+
+ @Override
+ public void handleNotification(Notification notification, Object handback) {
+ String nType = notification.getType();
+ String poolName
+ = CodeCacheUtils.getPoolNameFromNotification(notification);
+ // consider code cache events only
+ if (CodeCacheUtils.isAvailableCodeHeapPoolName(poolName)) {
+ Asserts.assertEQ(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED,
+ nType, "Unexpected event received: " + nType);
+ // receiving events from available CodeCache-related beans only
+ if (counters.get(poolName) != null) {
+ counters.get(poolName).incrementAndGet();
+ lastEventTimestamp = System.currentTimeMillis();
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/ThresholdNotificationsTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.Utils;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryNotificationInfo;
+import java.lang.management.MemoryPoolMXBean;
+import javax.management.ListenerNotFoundException;
+import javax.management.Notification;
+import javax.management.NotificationEmitter;
+import javax.management.NotificationListener;
+import sun.hotspot.code.BlobType;
+
+/*
+ * @test ThresholdNotificationsTest
+ * @library /testlibrary /../../test/lib
+ * @build ThresholdNotificationsTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing
+ * -XX:-MethodFlushing -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -XX:+SegmentedCodeCache -XX:CompileCommand=compileonly,null::*
+ * ThresholdNotificationsTest
+ * @summary testing of getUsageThreshold()
+ */
+public class ThresholdNotificationsTest implements NotificationListener {
+
+ private final static long WAIT_TIME = 10000L;
+ private volatile long counter;
+ private final BlobType btype;
+
+ public static void main(String[] args) {
+ for (BlobType bt : BlobType.getAvailable()) {
+ new ThresholdNotificationsTest(bt).runTest();
+ }
+ }
+
+ public ThresholdNotificationsTest(BlobType btype) {
+ this.btype = btype;
+ counter = 0L;
+ CodeCacheUtils.disableCollectionUsageThresholds();
+ }
+
+ @Override
+ public void handleNotification(Notification notification, Object handback) {
+ String nType = notification.getType();
+ String poolName
+ = CodeCacheUtils.getPoolNameFromNotification(notification);
+ // consider code cache events only
+ if (CodeCacheUtils.isAvailableCodeHeapPoolName(poolName)) {
+ Asserts.assertEQ(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED,
+ nType, "Unexpected event received: " + nType);
+ if (poolName.equals(btype.getMemoryPool().getName())) {
+ counter++;
+ }
+ }
+ }
+
+ protected void runTest() {
+ int iterationsCount =
+ Integer.getInteger("com.oracle.java.testlibrary.iterations", 1);
+ MemoryPoolMXBean bean = btype.getMemoryPool();
+ ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
+ addNotificationListener(this, null, null);
+ for (int i = 0; i < iterationsCount; i++) {
+ CodeCacheUtils.hitUsageThreshold(bean, btype);
+ }
+ Asserts.assertTrue(
+ Utils.waitForCondition(
+ () -> counter == iterationsCount, WAIT_TIME),
+ "Couldn't receive expected notifications count");
+ try {
+ ((NotificationEmitter) ManagementFactory.getMemoryMXBean()).
+ removeNotificationListener(this);
+ } catch (ListenerNotFoundException ex) {
+ throw new AssertionError("Can't remove notification listener", ex);
+ }
+ System.out.printf("INFO: Scenario finished successfully for %s%n",
+ bean.getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdExceededSeveralTimesTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test UsageThresholdExceededSeveralTimesTest
+ * @library /testlibrary /../../test/lib
+ * @build UsageThresholdExceededTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing
+ * -XX:-MethodFlushing -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -XX:+SegmentedCodeCache -XX:CompileCommand=compileonly,null::*
+ * -Dcom.oracle.java.testlibrary.iterations=10 UsageThresholdExceededTest
+ * @summary verifying that getUsageThresholdCount() returns correct value
+ * after threshold has been hit several times
+ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdExceededTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import java.lang.management.MemoryPoolMXBean;
+import sun.hotspot.code.BlobType;
+
+/*
+ * @test UsageThresholdExceededTest
+ * @library /testlibrary /../../test/lib
+ * @build UsageThresholdExceededTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:-UseCodeCacheFlushing
+ * -XX:-MethodFlushing -XX:CompileCommand=compileonly,null::*
+ * UsageThresholdExceededTest
+ * @summary verifying that getUsageThresholdCount() returns correct value
+ * after threshold has been hit
+ */
+public class UsageThresholdExceededTest {
+
+ protected final int iterations;
+ private final BlobType btype;
+
+ public UsageThresholdExceededTest(BlobType btype, int iterations) {
+ this.btype = btype;
+ this.iterations = iterations;
+ }
+
+ public static void main(String[] args) {
+ int iterationsCount =
+ Integer.getInteger("com.oracle.java.testlibrary.iterations", 1);
+ for (BlobType btype : BlobType.getAvailable()) {
+ if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
+ new UsageThresholdExceededTest(btype, iterationsCount)
+ .runTest();
+ }
+ }
+ }
+
+ protected void runTest() {
+ MemoryPoolMXBean bean = btype.getMemoryPool();
+ long oldValue = bean.getUsageThresholdCount();
+ for (int i = 0; i < iterations; i++) {
+ CodeCacheUtils.hitUsageThreshold(bean, btype);
+ }
+ Asserts.assertEQ(bean.getUsageThresholdCount(), oldValue + iterations,
+ "Unexpected threshold usage count");
+ System.out.printf("INFO: Scenario finished successfully for %s%n",
+ bean.getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdIncreasedTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import java.lang.management.MemoryPoolMXBean;
+import sun.hotspot.code.BlobType;
+
+/*
+ * @test UsageThresholdIncreasedTest
+ * @library /testlibrary /../../test/lib
+ * @build UsageThresholdIncreasedTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache -XX:-UseCodeCacheFlushing
+ * -XX:-MethodFlushing -XX:CompileCommand=compileonly,null::*
+ * UsageThresholdIncreasedTest
+ * @summary verifying that threshold hasn't been hit after allocation smaller
+ * than threshold value and that threshold value can be changed
+ */
+public class UsageThresholdIncreasedTest {
+
+ private static final int ALLOCATION_STEP = 5;
+ private static final long THRESHOLD_STEP = ALLOCATION_STEP
+ * CodeCacheUtils.MIN_ALLOCATION;
+ private final BlobType btype;
+
+ public UsageThresholdIncreasedTest(BlobType btype) {
+ this.btype = btype;
+ }
+
+ public static void main(String[] args) {
+ for (BlobType btype : BlobType.getAvailable()) {
+ new UsageThresholdIncreasedTest(btype).runTest();
+ }
+ }
+
+ private void checkUsageThresholdCount(MemoryPoolMXBean bean, long count){
+ Asserts.assertEQ(bean.getUsageThresholdCount(), count,
+ String.format("Usage threshold was hit: %d times for %s "
+ + "Threshold value: %d with current usage: %d",
+ bean.getUsageThresholdCount(), bean.getName(),
+ bean.getUsageThreshold(), bean.getUsage().getUsed()));
+ }
+
+ protected void runTest() {
+ long headerSize = CodeCacheUtils.getHeaderSize(btype);
+ long allocationUnit = CodeCacheUtils.MIN_ALLOCATION - headerSize;
+ MemoryPoolMXBean bean = btype.getMemoryPool();
+ long initialCount = bean.getUsageThresholdCount();
+ long initialSize = bean.getUsage().getUsed();
+ bean.setUsageThreshold(initialSize + THRESHOLD_STEP);
+ for (int i = 0; i < ALLOCATION_STEP - 1; i++) {
+ CodeCacheUtils.WB.allocateCodeBlob(allocationUnit, btype.id);
+ }
+ // Usage threshold check is triggered by GC cycle, so, call it
+ CodeCacheUtils.WB.fullGC();
+ checkUsageThresholdCount(bean, initialCount);
+ long filledSize = bean.getUsage().getUsed();
+ bean.setUsageThreshold(filledSize + THRESHOLD_STEP);
+ for (int i = 0; i < ALLOCATION_STEP - 1; i++) {
+ CodeCacheUtils.WB.allocateCodeBlob(allocationUnit, btype.id);
+ }
+ CodeCacheUtils.WB.fullGC();
+ checkUsageThresholdCount(bean, initialCount);
+ System.out.println("INFO: Case finished successfully for " + bean.getName());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/jmx/UsageThresholdNotExceededTest.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import java.lang.management.MemoryPoolMXBean;
+import sun.hotspot.code.BlobType;
+
+/*
+ * @test UsageThresholdNotExceededTest
+ * @library /testlibrary /../../test/lib
+ * @build UsageThresholdNotExceededTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing
+ * -XX:-MethodFlushing -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -XX:+SegmentedCodeCache -XX:CompileCommand=compileonly,null::*
+ * UsageThresholdNotExceededTest
+ * @summary verifying that usage threshold not exceeded while allocating less
+ * than usage threshold
+ */
+public class UsageThresholdNotExceededTest {
+
+ private final BlobType btype;
+
+ public UsageThresholdNotExceededTest(BlobType btype) {
+ this.btype = btype;
+ }
+
+ public static void main(String[] args) {
+ for (BlobType btype : BlobType.getAvailable()) {
+ if (CodeCacheUtils.isCodeHeapPredictable(btype)) {
+ new UsageThresholdNotExceededTest(btype).runTest();
+ }
+ }
+ }
+
+ protected void runTest() {
+ MemoryPoolMXBean bean = btype.getMemoryPool();
+ long initialThresholdCount = bean.getUsageThresholdCount();
+ long initialUsage = bean.getUsage().getUsed();
+ bean.setUsageThreshold(initialUsage + 1 + CodeCacheUtils.MIN_ALLOCATION);
+ CodeCacheUtils.WB.allocateCodeBlob(CodeCacheUtils.MIN_ALLOCATION
+ - CodeCacheUtils.getHeaderSize(btype), btype.id);
+ // a gc cycle triggers usage threshold recalculation
+ CodeCacheUtils.WB.fullGC();
+ Asserts.assertEQ(bean.getUsageThresholdCount(), initialThresholdCount,
+ String.format("Usage threshold was hit: %d times for %s. "
+ + "Threshold value: %d with current usage: %d",
+ bean.getUsageThresholdCount(), bean.getName(),
+ bean.getUsageThreshold(), bean.getUsage().getUsed()));
+
+ System.out.println("INFO: Case finished successfully for "
+ + bean.getName());
+ }
+}
--- a/hotspot/test/compiler/rtm/locking/TestRTMAbortRatio.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMAbortRatio.java Fri Jan 16 12:33:47 2015 -0800
@@ -127,10 +127,7 @@
@Override
public String[] getMethodsToCompileNames() {
- return new String[] {
- getMethodWithLockName(),
- Unsafe.class.getName() + "::addressSize"
- };
+ return new String[] { getMethodWithLockName() };
}
public void lock(boolean abort) {
@@ -148,10 +145,12 @@
public static void main(String args[]) throws Throwable {
Asserts.assertGTE(args.length, 1, "One argument required.");
Test t = new Test();
- if (Boolean.valueOf(args[0])) {
+ boolean shouldBeInflated = Boolean.valueOf(args[0]);
+ if (shouldBeInflated) {
AbortProvoker.inflateMonitor(t.monitor);
}
for (int i = 0; i < Test.TOTAL_ITERATIONS; i++) {
+ AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated);
t.lock(i >= Test.WARMUP_ITERATIONS);
}
}
--- a/hotspot/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMAfterNonRTMDeopt.java Fri Jan 16 12:33:47 2015 -0800
@@ -157,10 +157,7 @@
@Override
public String[] getMethodsToCompileNames() {
- return new String[] {
- getMethodWithLockName(),
- sun.misc.Unsafe.class.getName() + "::forceAbort"
- };
+ return new String[] { getMethodWithLockName() };
}
public void forceAbort(int a[], boolean abort) {
@@ -183,13 +180,15 @@
public static void main(String args[]) throws Throwable {
Test t = new Test();
- if (Boolean.valueOf(args[0])) {
+ boolean shouldBeInflated = Boolean.valueOf(args[0]);
+ if (shouldBeInflated) {
AbortProvoker.inflateMonitor(t.monitor);
}
int tmp[] = new int[1];
for (int i = 0; i < Test.ITERATIONS; i++ ) {
+ AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated);
if (i == Test.RANGE_CHECK_AT) {
t.forceAbort(new int[0], false);
} else {
--- a/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMDeoptOnLowAbortRatio.java Fri Jan 16 12:33:47 2015 -0800
@@ -130,10 +130,7 @@
@Override
public String[] getMethodsToCompileNames() {
- return new String[] {
- getMethodWithLockName(),
- sun.misc.Unsafe.class.getName() + "::addressSize"
- };
+ return new String[] { getMethodWithLockName() };
}
public void forceAbort(boolean abort) {
@@ -151,11 +148,12 @@
public static void main(String args[]) throws Throwable {
Asserts.assertGTE(args.length, 1, "One argument required.");
Test t = new Test();
-
- if (Boolean.valueOf(args[0])) {
+ boolean shouldBeInflated = Boolean.valueOf(args[0]);
+ if (shouldBeInflated) {
AbortProvoker.inflateMonitor(t.monitor);
}
for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) {
+ AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated);
t.forceAbort(
i == TestRTMDeoptOnLowAbortRatio.LOCKING_THRESHOLD);
}
--- a/hotspot/test/compiler/rtm/locking/TestRTMLockingThreshold.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMLockingThreshold.java Fri Jan 16 12:33:47 2015 -0800
@@ -143,10 +143,7 @@
@Override
public String[] getMethodsToCompileNames() {
- return new String[] {
- getMethodWithLockName(),
- sun.misc.Unsafe.class.getName() + "::addressSize"
- };
+ return new String[] { getMethodWithLockName() };
}
public void lock(boolean abort) {
@@ -164,11 +161,12 @@
public static void main(String args[]) throws Throwable {
Asserts.assertGTE(args.length, 1, "One argument required.");
Test t = new Test();
-
- if (Boolean.valueOf(args[0])) {
+ boolean shouldBeInflated = Boolean.valueOf(args[0]);
+ if (shouldBeInflated) {
AbortProvoker.inflateMonitor(t.monitor);
}
for (int i = 0; i < Test.TOTAL_ITERATIONS; i++) {
+ AbortProvoker.verifyMonitorState(t.monitor, shouldBeInflated);
t.lock(i % 2 == 1);
}
}
--- a/hotspot/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestRTMTotalCountIncrRate.java Fri Jan 16 12:33:47 2015 -0800
@@ -117,9 +117,7 @@
@Override
public String[] getMethodsToCompileNames() {
- return new String[] {
- getMethodWithLockName()
- };
+ return new String[] { getMethodWithLockName() };
}
public void lock() {
@@ -135,11 +133,13 @@
public static void main(String args[]) throws Throwable {
Asserts.assertGTE(args.length, 1, "One argument required.");
Test test = new Test();
-
- if (Boolean.valueOf(args[0])) {
+ boolean shouldBeInflated = Boolean.valueOf(args[0]);
+ if (shouldBeInflated) {
AbortProvoker.inflateMonitor(test.monitor);
}
for (long i = 0L; i < Test.TOTAL_ITERATIONS; i++) {
+ AbortProvoker.verifyMonitorState(test.monitor,
+ shouldBeInflated);
test.lock();
}
}
--- a/hotspot/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/rtm/locking/TestUseRTMAfterLockInflation.java Fri Jan 16 12:33:47 2015 -0800
@@ -52,7 +52,7 @@
* Compiled method invoked {@code AbortProvoker.DEFAULT_ITERATIONS} times before
* lock inflation and the same amount of times after inflation.
* As a result total locks count should be equal to
- * {@code 2*AbortProvoker.DEFAULT_ITERATIONS}.
+ * {@code 2 * AbortProvoker.DEFAULT_ITERATIONS}.
* It is a pretty strict assertion which could fail if some retriable abort
* happened: it could be {@code AbortType.RETRIABLE} or
* {@code AbortType.MEM_CONFLICT}, but unfortunately abort can has both these
@@ -101,7 +101,6 @@
}
public static class Test {
-
/**
* Usage:
* Test <provoker type>
@@ -113,10 +112,12 @@
AbortProvoker provoker
= AbortType.lookup(Integer.valueOf(args[0])).provoker();
for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) {
+ AbortProvoker.verifyMonitorState(provoker, false /*deflated*/);
provoker.forceAbort();
}
provoker.inflateMonitor();
for (int i = 0; i < AbortProvoker.DEFAULT_ITERATIONS; i++) {
+ AbortProvoker.verifyMonitorState(provoker, true /*inflated*/);
provoker.forceAbort();
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/testlibrary/CompilerUtils.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.Platform;
+import java.util.stream.IntStream;
+import sun.hotspot.WhiteBox;
+
+public class CompilerUtils {
+
+ private CompilerUtils() {
+ // to prevent from instantiation
+ }
+
+ /**
+ * Returns available compilation levels
+ *
+ * @return int array with compilation levels
+ */
+ public static int[] getAvailableCompilationLevels() {
+ if (!WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompiler")) {
+ return new int[0];
+ }
+ if (WhiteBox.getWhiteBox().getBooleanVMFlag("TieredCompilation")) {
+ Long flagValue = WhiteBox.getWhiteBox()
+ .getIntxVMFlag("TieredStopAtLevel");
+ int maxLevel = flagValue.intValue();
+ Asserts.assertEQ(new Long(maxLevel), flagValue,
+ "TieredStopAtLevel has value out of int capacity");
+ return IntStream.rangeClosed(1, maxLevel).toArray();
+ } else {
+ if (Platform.isServer()) {
+ return new int[]{4};
+ }
+ if (Platform.isClient() || Platform.isMinimal()) {
+ return new int[]{1};
+ }
+ }
+ return new int[0];
+ }
+}
--- a/hotspot/test/compiler/testlibrary/rtm/AbortProvoker.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/testlibrary/rtm/AbortProvoker.java Fri Jan 16 12:33:47 2015 -0800
@@ -29,8 +29,7 @@
import java.util.concurrent.CyclicBarrier;
import com.oracle.java.testlibrary.Asserts;
-import com.oracle.java.testlibrary.Utils;
-import sun.misc.Unsafe;
+import sun.hotspot.WhiteBox;
/**
* Base class for different transactional execution abortion
@@ -38,6 +37,9 @@
*/
public abstract class AbortProvoker implements CompilableTest {
public static final long DEFAULT_ITERATIONS = 10000L;
+ private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+ @SuppressWarnings("unused")
+ private static int sharedState = 0;
/**
* Inflates monitor associated with object {@code monitor}.
* Inflation is forced by entering the same monitor from
@@ -48,36 +50,76 @@
* @throws Exception if something went wrong.
*/
public static Object inflateMonitor(Object monitor) throws Exception {
- Unsafe unsafe = Utils.getUnsafe();
CyclicBarrier barrier = new CyclicBarrier(2);
Runnable inflatingRunnable = () -> {
- unsafe.monitorEnter(monitor);
- try {
- barrier.await();
- barrier.await();
- } catch (InterruptedException | BrokenBarrierException e) {
- throw new RuntimeException(
- "Synchronization issue occurred.", e);
- } finally {
- unsafe.monitorExit(monitor);
+ synchronized (monitor) {
+ try {
+ barrier.await();
+ } catch (BrokenBarrierException | InterruptedException e) {
+ throw new RuntimeException(
+ "Synchronization issue occurred.", e);
+ }
+ try {
+ monitor.wait();
+ } catch (InterruptedException e) {
+ throw new AssertionError("The thread waiting on an"
+ + " inflated monitor was interrupted, thus test"
+ + " results may be incorrect.", e);
+ }
}
};
Thread t = new Thread(inflatingRunnable);
+ t.setDaemon(true);
t.start();
// Wait until thread t enters the monitor.
barrier.await();
- // At this point monitor will be owned by thread t,
- // so our attempt to enter the same monitor will force
- // monitor inflation.
- Asserts.assertFalse(unsafe.tryMonitorEnter(monitor),
- "Not supposed to enter the monitor first");
- barrier.await();
- t.join();
+ synchronized (monitor) {
+ // At this point thread t is already waiting on the monitor.
+ // Modifying static field just to avoid lock's elimination.
+ sharedState++;
+ }
+ verifyMonitorState(monitor, true /* inflated */);
return monitor;
}
+ /**
+ * Verifies that {@code monitor} is a stack-lock or inflated lock depending
+ * on {@code shouldBeInflated} value. If {@code monitor} is inflated while
+ * it is expected that it should be a stack-lock, then this method attempts
+ * to deflate it by forcing a safepoint and then verifies the state once
+ * again.
+ *
+ * @param monitor monitor to be verified.
+ * @param shouldBeInflated flag indicating whether or not monitor is
+ * expected to be inflated.
+ * @throws RuntimeException if the {@code monitor} in a wrong state.
+ */
+ public static void verifyMonitorState(Object monitor,
+ boolean shouldBeInflated) {
+ if (!shouldBeInflated && WHITE_BOX.isMonitorInflated(monitor)) {
+ WHITE_BOX.forceSafepoint();
+ }
+ Asserts.assertEQ(WHITE_BOX.isMonitorInflated(monitor), shouldBeInflated,
+ "Monitor in a wrong state.");
+ }
+ /**
+ * Verifies that monitor used by the {@code provoker} is a stack-lock or
+ * inflated lock depending on {@code shouldBeInflated} value. If such
+ * monitor is inflated while it is expected that it should be a stack-lock,
+ * then this method attempts to deflate it by forcing a safepoint and then
+ * verifies the state once again.
+ *
+ * @param provoker AbortProvoker whose monitor's state should be verified.
+ * @param shouldBeInflated flag indicating whether or not monitor is
+ * expected to be inflated.
+ * @throws RuntimeException if the {@code monitor} in a wrong state.
+ */
+ public static void verifyMonitorState(AbortProvoker provoker,
+ boolean shouldBeInflated) {
+ verifyMonitorState(provoker.monitor, shouldBeInflated);
+ }
/**
* Get instance of specified AbortProvoker, inflate associated monitor
@@ -120,6 +162,7 @@
}
for (long i = 0; i < iterations; i++) {
+ AbortProvoker.verifyMonitorState(provoker, monitorShouldBeInflated);
provoker.forceAbort();
}
}
--- a/hotspot/test/compiler/testlibrary/rtm/BusyLock.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/testlibrary/rtm/BusyLock.java Fri Jan 16 12:33:47 2015 -0800
@@ -77,7 +77,7 @@
}
}
- public void test() {
+ public void syncAndTest() {
try {
barrier.await();
// wait until monitor is locked by a ::run method
@@ -85,6 +85,10 @@
} catch (InterruptedException | BrokenBarrierException e) {
throw new RuntimeException("Synchronization error happened.", e);
}
+ test();
+ }
+
+ public void test() {
synchronized(monitor) {
BusyLock.field++;
}
@@ -130,7 +134,7 @@
Thread t = new Thread(busyLock);
t.start();
- busyLock.test();
+ busyLock.syncAndTest();
t.join();
}
}
--- a/hotspot/test/compiler/testlibrary/rtm/MemoryConflictProvoker.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/testlibrary/rtm/MemoryConflictProvoker.java Fri Jan 16 12:33:47 2015 -0800
@@ -69,11 +69,6 @@
* Accesses and modifies memory region from within the transaction.
*/
public void transactionalRegion() {
- try {
- barrier.await();
- } catch (InterruptedException | BrokenBarrierException e) {
- throw new RuntimeException(e);
- }
for (int i = 0; i < MemoryConflictProvoker.INNER_ITERATIONS; i++) {
synchronized(monitor) {
MemoryConflictProvoker.field--;
@@ -86,6 +81,11 @@
try {
Thread t = new Thread(conflictingThread);
t.start();
+ try {
+ barrier.await();
+ } catch (InterruptedException | BrokenBarrierException e) {
+ throw new RuntimeException(e);
+ }
transactionalRegion();
t.join();
} catch (Exception e) {
--- a/hotspot/test/compiler/testlibrary/rtm/RTMTestBase.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/compiler/testlibrary/rtm/RTMTestBase.java Fri Jan 16 12:33:47 2015 -0800
@@ -240,7 +240,8 @@
Collections.addAll(finalVMOpts, "-Xcomp", "-server",
"-XX:-TieredCompilation", "-XX:+UseRTMLocking",
CommandLineOptionTest.UNLOCK_DIAGNOSTIC_VM_OPTIONS,
- CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS);
+ CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
+ "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI");
if (test != null) {
for (String method : test.getMethodsToCompileNames()) {
--- a/hotspot/test/gc/g1/TestEagerReclaimHumongousRegions2.java Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test TestEagerReclaimHumongousRegions2
- * @bug 8051973
- * @summary Test to make sure that eager reclaim of humongous objects correctly clears
- * mark bitmaps at reclaim.
- * @key gc
- * @library /testlibrary
- */
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.Random;
-
-import com.oracle.java.testlibrary.OutputAnalyzer;
-import com.oracle.java.testlibrary.ProcessTools;
-
-// An object that has a few references to other instances to slow down marking.
-class ObjectWithSomeRefs {
- public ObjectWithSomeRefs other1;
- public ObjectWithSomeRefs other2;
- public ObjectWithSomeRefs other3;
- public ObjectWithSomeRefs other4;
-}
-
-class ReclaimRegionFast {
- public static final long MAX_MILLIS_FOR_RUN = 50 * 1000; // The maximum runtime for the actual test.
-
- public static final int M = 1024*1024;
-
- public static LinkedList<Object> garbageList = new LinkedList<Object>();
-
- public static void genGarbage(Object large) {
- for (int i = 0; i < 64*1024; i++) {
- Object[] garbage = new Object[50];
- garbage[0] = large;
- garbageList.add(garbage);
- }
- garbageList.clear();
- }
-
- public static ArrayList<ObjectWithSomeRefs> longList = new ArrayList<ObjectWithSomeRefs>();
-
- public static void main(String[] args) {
-
- for (int i = 0; i < 16*1024; i++) {
- longList.add(new ObjectWithSomeRefs());
- }
-
- Random rnd = new Random();
- for (int i = 0; i < longList.size(); i++) {
- int len = longList.size();
- longList.get(i).other1 = longList.get(rnd.nextInt(len));
- longList.get(i).other2 = longList.get(rnd.nextInt(len));
- longList.get(i).other3 = longList.get(rnd.nextInt(len));
- longList.get(i).other4 = longList.get(rnd.nextInt(len));
- }
-
- int[] large1 = new int[M];
- int[] large2 = null;
- int[] large3 = null;
- int[] large4 = null;
-
- Object ref_from_stack = large1;
-
- long start_millis = System.currentTimeMillis();
-
- for (int i = 0; i < 20; i++) {
- long current_millis = System.currentTimeMillis();
- if ((current_millis - start_millis) > MAX_MILLIS_FOR_RUN) {
- System.out.println("Finishing test because maximum runtime exceeded");
- break;
- }
- // A set of large objects that will be reclaimed eagerly - and hopefully marked.
- large1 = new int[M - 20];
- large2 = new int[M - 20];
- large3 = new int[M - 20];
- large4 = new int[M - 20];
- genGarbage(large1);
- // Make sure that the compiler cannot completely remove
- // the allocation of the large object until here.
- System.out.println(large1 + " " + large2 + " " + large3 + " " + large4);
- }
-
- // Keep the reference to the first object alive.
- System.out.println(ref_from_stack);
- }
-}
-
-public class TestEagerReclaimHumongousRegions2 {
- public static void main(String[] args) throws Exception {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-XX:+UseG1GC",
- "-Xms128M",
- "-Xmx128M",
- "-Xmn2M",
- "-XX:G1HeapRegionSize=1M",
- "-XX:InitiatingHeapOccupancyPercent=0", // Want to have as much as possible initial marks.
- "-XX:+PrintGC",
- "-XX:+VerifyAfterGC",
- "-XX:ConcGCThreads=1", // Want to make marking as slow as possible.
- "-XX:+IgnoreUnrecognizedVMOptions", // G1VerifyBitmaps is develop only.
- "-XX:+G1VerifyBitmaps",
- ReclaimRegionFast.class.getName());
- OutputAnalyzer output = new OutputAnalyzer(pb.start());
- output.shouldHaveExitValue(0);
- }
-}
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsClearMarkBits.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestEagerReclaimHumongousRegionsClearMarkBits
+ * @bug 8051973
+ * @summary Test to make sure that eager reclaim of humongous objects correctly clears
+ * mark bitmaps at reclaim.
+ * @key gc
+ * @library /testlibrary
+ */
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.Random;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.ProcessTools;
+
+// An object that has a few references to other instances to slow down marking.
+class ObjectWithSomeRefs {
+ public ObjectWithSomeRefs other1;
+ public ObjectWithSomeRefs other2;
+ public ObjectWithSomeRefs other3;
+ public ObjectWithSomeRefs other4;
+}
+
+class ReclaimRegionFast {
+ public static final long MAX_MILLIS_FOR_RUN = 50 * 1000; // The maximum runtime for the actual test.
+
+ public static final int M = 1024*1024;
+
+ public static LinkedList<Object> garbageList = new LinkedList<Object>();
+
+ public static void genGarbage(Object large) {
+ for (int i = 0; i < 64*1024; i++) {
+ Object[] garbage = new Object[50];
+ garbage[0] = large;
+ garbageList.add(garbage);
+ }
+ garbageList.clear();
+ }
+
+ public static ArrayList<ObjectWithSomeRefs> longList = new ArrayList<ObjectWithSomeRefs>();
+
+ public static void main(String[] args) {
+
+ for (int i = 0; i < 16*1024; i++) {
+ longList.add(new ObjectWithSomeRefs());
+ }
+
+ Random rnd = new Random();
+ for (int i = 0; i < longList.size(); i++) {
+ int len = longList.size();
+ longList.get(i).other1 = longList.get(rnd.nextInt(len));
+ longList.get(i).other2 = longList.get(rnd.nextInt(len));
+ longList.get(i).other3 = longList.get(rnd.nextInt(len));
+ longList.get(i).other4 = longList.get(rnd.nextInt(len));
+ }
+
+ int[] large1 = new int[M];
+ int[] large2 = null;
+ int[] large3 = null;
+ int[] large4 = null;
+
+ Object ref_from_stack = large1;
+
+ long start_millis = System.currentTimeMillis();
+
+ for (int i = 0; i < 20; i++) {
+ long current_millis = System.currentTimeMillis();
+ if ((current_millis - start_millis) > MAX_MILLIS_FOR_RUN) {
+ System.out.println("Finishing test because maximum runtime exceeded");
+ break;
+ }
+ // A set of large objects that will be reclaimed eagerly - and hopefully marked.
+ large1 = new int[M - 20];
+ large2 = new int[M - 20];
+ large3 = new int[M - 20];
+ large4 = new int[M - 20];
+ genGarbage(large1);
+ // Make sure that the compiler cannot completely remove
+ // the allocation of the large object until here.
+ System.out.println(large1 + " " + large2 + " " + large3 + " " + large4);
+ }
+
+ // Keep the reference to the first object alive.
+ System.out.println(ref_from_stack);
+ }
+}
+
+public class TestEagerReclaimHumongousRegionsClearMarkBits {
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+UseG1GC",
+ "-Xms128M",
+ "-Xmx128M",
+ "-Xmn2M",
+ "-XX:G1HeapRegionSize=1M",
+ "-XX:InitiatingHeapOccupancyPercent=0", // Want to have as much as possible initial marks.
+ "-XX:+PrintGC",
+ "-XX:+VerifyAfterGC",
+ "-XX:ConcGCThreads=1", // Want to make marking as slow as possible.
+ "-XX:+IgnoreUnrecognizedVMOptions", // G1VerifyBitmaps is develop only.
+ "-XX:+G1VerifyBitmaps",
+ ReclaimRegionFast.class.getName());
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldHaveExitValue(0);
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/TestEagerReclaimHumongousRegionsWithRefs.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestEagerReclaimHumongousRegionsWithRefs
+ * @bug 8048179
+ * @summary Test to make sure that eager reclaim of humongous objects that have previously
+ * been referenced by other old gen regions work. We simply try to fill
+ * up the heap with humongous objects and create a remembered set entry from an object by
+ * referencing that we know is in the old gen. After changing this reference, the object
+ * should still be eagerly reclaimable to avoid Full GC.
+ * @key gc
+ * @library /testlibrary
+ */
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.LinkedList;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.ProcessTools;
+import static com.oracle.java.testlibrary.Asserts.*;
+
+class RefHolder {
+ Object ref;
+}
+
+class ReclaimRegionFast {
+
+ public static final int M = 1024*1024;
+
+ public static LinkedList<Object> garbageList = new LinkedList<Object>();
+
+ public static void genGarbage() {
+ for (int i = 0; i < 32*1024; i++) {
+ garbageList.add(new int[100]);
+ }
+ garbageList.clear();
+ }
+
+
+ // A large object referenced by a static.
+ static int[] filler = new int[10 * M];
+
+ // Old gen object referencing the large object, generating remembered
+ // set entries.
+ static RefHolder fromOld = new RefHolder();
+
+ public static void main(String[] args) {
+
+ int[] large = new int[M];
+
+ Object ref_from_stack = large;
+
+ for (int i = 0; i < 100; i++) {
+ // A large object that will be reclaimed eagerly.
+ large = new int[6*M];
+ fromOld.ref = large;
+ genGarbage();
+ }
+
+ // Keep the reference to the first object alive.
+ System.out.println(ref_from_stack);
+ }
+}
+
+public class TestEagerReclaimHumongousRegionsWithRefs {
+
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+UseG1GC",
+ "-Xms128M",
+ "-Xmx128M",
+ "-Xmn16M",
+ "-XX:+PrintGC",
+ ReclaimRegionFast.class.getName());
+
+ Pattern p = Pattern.compile("Full GC");
+
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+ int found = 0;
+ Matcher m = p.matcher(output.getStdout());
+ while (m.find()) {
+ found++;
+ }
+ System.out.println("Issued " + found + " Full GCs");
+
+ assertLessThan(found, 10, "Found that " + found + " Full GCs were issued. This is larger than the bound. Eager reclaim of objects once referenced from old gen seems to not work at all");
+ output.shouldHaveExitValue(0);
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/TestG1TraceEagerReclaimHumongousObjects.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestG1TraceEagerReclaimHumongousObjects
+ * @bug 8058801 8048179
+ * @summary Ensure that the output for a G1TraceEagerReclaimHumongousObjects
+ * includes the expected necessary messages.
+ * @key gc
+ * @library /testlibrary
+ */
+
+import com.oracle.java.testlibrary.ProcessTools;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import java.util.LinkedList;
+
+public class TestG1TraceEagerReclaimHumongousObjects {
+ public static void main(String[] args) throws Exception {
+ testGCLogs();
+ testHumongousObjectGCLogs();
+ }
+
+ private static void testGCLogs() throws Exception {
+
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
+ "-Xms128M",
+ "-Xmx128M",
+ "-Xmn16M",
+ "-XX:G1HeapRegionSize=1M",
+ "-XX:+PrintGC",
+ "-XX:+UnlockExperimentalVMOptions",
+ "-XX:G1LogLevel=finest",
+ "-XX:+G1TraceEagerReclaimHumongousObjects",
+ GCTest.class.getName());
+
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+ // As G1EagerReclaimHumongousObjects is set(default), below logs should be displayed.
+ // And GCTest doesn't have humongous objects, so values should be zero.
+ output.shouldContain("[Humongous Reclaim");
+ output.shouldContain("[Humongous Total: 0]");
+ output.shouldContain("[Humongous Candidate: 0]");
+ output.shouldContain("[Humongous Reclaimed: 0]");
+
+ output.shouldHaveExitValue(0);
+ }
+
+ private static void testHumongousObjectGCLogs() throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
+ "-Xms128M",
+ "-Xmx128M",
+ "-Xmn16M",
+ "-XX:G1HeapRegionSize=1M",
+ "-XX:+PrintGC",
+ "-XX:+UnlockExperimentalVMOptions",
+ "-XX:G1LogLevel=finest",
+ "-XX:+G1TraceEagerReclaimHumongousObjects",
+ GCWithHumongousObjectTest.class.getName());
+
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+ // As G1ReclaimDeadHumongousObjectsAtYoungGC is set(default), below logs should be displayed.
+ output.shouldContain("[Humongous Reclaim");
+ output.shouldContain("[Humongous Total");
+ output.shouldContain("[Humongous Candidate");
+ output.shouldContain("[Humongous Reclaimed");
+
+ // As G1TraceReclaimDeadHumongousObjectsAtYoungGC is set and GCWithHumongousObjectTest has humongous objects,
+ // these logs should be displayed.
+ output.shouldContain("Live humongous");
+ output.shouldContain("Dead humongous region");
+ output.shouldHaveExitValue(0);
+ }
+
+ static class GCTest {
+ private static byte[] garbage;
+
+ public static void main(String [] args) {
+ System.out.println("Creating garbage");
+ // create 128MB of garbage. This should result in at least one GC
+ for (int i = 0; i < 1024; i++) {
+ garbage = new byte[128 * 1024];
+ }
+ System.out.println("Done");
+ }
+ }
+
+ static class GCWithHumongousObjectTest {
+
+ public static final int M = 1024*1024;
+ public static LinkedList<Object> garbageList = new LinkedList<Object>();
+ // A large object referenced by a static.
+ static int[] filler = new int[10 * M];
+
+ public static void genGarbage() {
+ for (int i = 0; i < 32*1024; i++) {
+ garbageList.add(new int[100]);
+ }
+ garbageList.clear();
+ }
+
+ public static void main(String[] args) {
+
+ int[] large = new int[M];
+ Object ref = large;
+
+ System.out.println("Creating garbage");
+ for (int i = 0; i < 100; i++) {
+ // A large object that will be reclaimed eagerly.
+ large = new int[6*M];
+ genGarbage();
+ // Make sure that the compiler cannot completely remove
+ // the allocation of the large object until here.
+ System.out.println(large);
+ }
+
+ // Keep the reference to the first object alive.
+ System.out.println(ref);
+ System.out.println("Done");
+ }
+ }
+}
--- a/hotspot/test/gc/g1/TestG1TraceReclaimDeadHumongousObjectsAtYoungGC.java Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test TestG1TraceReclaimDeadHumongousObjectsAtYoungGC
- * @bug 8058801
- * @summary Ensure that the output for a G1TraceReclaimDeadHumongousObjectsAtYoungGC
- * includes the expected necessary messages.
- * @key gc
- * @library /testlibrary
- */
-
-import com.oracle.java.testlibrary.ProcessTools;
-import com.oracle.java.testlibrary.OutputAnalyzer;
-import java.util.LinkedList;
-
-public class TestG1TraceReclaimDeadHumongousObjectsAtYoungGC {
- public static void main(String[] args) throws Exception {
- testGCLogs();
- testHumongousObjectGCLogs();
- }
-
- private static void testGCLogs() throws Exception {
-
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
- "-Xms128M",
- "-Xmx128M",
- "-Xmn16M",
- "-XX:G1HeapRegionSize=1M",
- "-XX:+PrintGC",
- "-XX:+UnlockExperimentalVMOptions",
- "-XX:G1LogLevel=finest",
- "-XX:+G1TraceReclaimDeadHumongousObjectsAtYoungGC",
- GCTest.class.getName());
-
- OutputAnalyzer output = new OutputAnalyzer(pb.start());
-
- // As G1ReclaimDeadHumongousObjectsAtYoungGC is set(default), below logs should be displayed.
- // And GCTest doesn't have humongous objects, so values should be zero.
- output.shouldContain("[Humongous Reclaim");
- output.shouldContain("[Humongous Total: 0]");
- output.shouldContain("[Humongous Candidate: 0]");
- output.shouldContain("[Humongous Reclaimed: 0]");
-
- output.shouldHaveExitValue(0);
- }
-
- private static void testHumongousObjectGCLogs() throws Exception {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
- "-Xms128M",
- "-Xmx128M",
- "-Xmn16M",
- "-XX:G1HeapRegionSize=1M",
- "-XX:+PrintGC",
- "-XX:+UnlockExperimentalVMOptions",
- "-XX:G1LogLevel=finest",
- "-XX:+G1TraceReclaimDeadHumongousObjectsAtYoungGC",
- GCWithHumongousObjectTest.class.getName());
-
- OutputAnalyzer output = new OutputAnalyzer(pb.start());
-
- // As G1ReclaimDeadHumongousObjectsAtYoungGC is set(default), below logs should be displayed.
- output.shouldContain("[Humongous Reclaim");
- output.shouldContain("[Humongous Total");
- output.shouldContain("[Humongous Candidate");
- output.shouldContain("[Humongous Reclaimed");
-
- // As G1TraceReclaimDeadHumongousObjectsAtYoungGC is set and GCWithHumongousObjectTest has humongous objects,
- // these logs should be displayed.
- output.shouldContain("Live humongous");
- output.shouldContain("Reclaim humongous region");
- output.shouldHaveExitValue(0);
- }
-
- static class GCTest {
- private static byte[] garbage;
-
- public static void main(String [] args) {
- System.out.println("Creating garbage");
- // create 128MB of garbage. This should result in at least one GC
- for (int i = 0; i < 1024; i++) {
- garbage = new byte[128 * 1024];
- }
- System.out.println("Done");
- }
- }
-
- static class GCWithHumongousObjectTest {
-
- public static final int M = 1024*1024;
- public static LinkedList<Object> garbageList = new LinkedList<Object>();
- // A large object referenced by a static.
- static int[] filler = new int[10 * M];
-
- public static void genGarbage() {
- for (int i = 0; i < 32*1024; i++) {
- garbageList.add(new int[100]);
- }
- garbageList.clear();
- }
-
- public static void main(String[] args) {
-
- int[] large = new int[M];
- Object ref = large;
-
- System.out.println("Creating garbage");
- for (int i = 0; i < 100; i++) {
- // A large object that will be reclaimed eagerly.
- large = new int[6*M];
- genGarbage();
- // Make sure that the compiler cannot completely remove
- // the allocation of the large object until here.
- System.out.println(large);
- }
-
- // Keep the reference to the first object alive.
- System.out.println(ref);
- System.out.println("Done");
- }
- }
-}
--- a/hotspot/test/gc/g1/TestGCLogMessages.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/gc/g1/TestGCLogMessages.java Fri Jan 16 12:33:47 2015 -0800
@@ -23,7 +23,7 @@
/*
* @test TestGCLogMessages
- * @bug 8035406 8027295 8035398 8019342 8027959
+ * @bug 8035406 8027295 8035398 8019342 8027959 8048179
* @summary Ensure that the PrintGCDetails output for a minor GC with G1
* includes the expected necessary messages.
* @key gc
@@ -54,6 +54,7 @@
output.shouldNotContain("[String Dedup Fixup");
output.shouldNotContain("[Young Free CSet");
output.shouldNotContain("[Non-Young Free CSet");
+ output.shouldNotContain("[Humongous Register");
output.shouldNotContain("[Humongous Reclaim");
output.shouldHaveExitValue(0);
@@ -72,9 +73,10 @@
output.shouldContain("[String Dedup Fixup");
output.shouldNotContain("[Young Free CSet");
output.shouldNotContain("[Non-Young Free CSet");
- output.shouldContain("[Humongous Reclaim");
+ output.shouldContain("[Humongous Register");
output.shouldNotContain("[Humongous Total");
output.shouldNotContain("[Humongous Candidate");
+ output.shouldContain("[Humongous Reclaim");
output.shouldNotContain("[Humongous Reclaimed");
output.shouldHaveExitValue(0);
@@ -95,9 +97,10 @@
output.shouldContain("[String Dedup Fixup");
output.shouldContain("[Young Free CSet");
output.shouldContain("[Non-Young Free CSet");
- output.shouldContain("[Humongous Reclaim");
+ output.shouldContain("[Humongous Register");
output.shouldContain("[Humongous Total");
output.shouldContain("[Humongous Candidate");
+ output.shouldContain("[Humongous Reclaim");
output.shouldContain("[Humongous Reclaimed");
output.shouldHaveExitValue(0);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/BadObjectClass/BootstrapRedefine.java Fri Jan 16 12:33:47 2015 -0800
@@ -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.
+ */
+
+/*
+ * @test
+ * @bug 6583051
+ * @summary Give error if java.lang.Object has been incompatibly overridden on the bootpath
+ * @library /testlibrary
+ * @compile Object.java
+ * @run main BootstrapRedefine
+ */
+
+import com.oracle.java.testlibrary.*;
+
+public class BootstrapRedefine {
+
+ public static void main(String[] args) throws Exception {
+ String testClasses = System.getProperty("test.classes", ".");
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xbootclasspath/p:" + testClasses, "-version");
+ new OutputAnalyzer(pb.start())
+ .shouldContain("Incompatible definition of java.lang.Object")
+ .shouldHaveExitValue(1);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/BadObjectClass/Object.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,37 @@
+/*
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 java.lang;
+
+/**
+ * This is a fake java.lang.Object class.
+ */
+public class Object {
+
+ // Add some methods
+ void dummy1() { return; }
+ void dummy2() { return; }
+ void dummy3() { return; }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/CommandLine/TestNullTerminatedFlags.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.*;
+
+/*
+ * @test TestNullTerminatedFlags
+ * @bug 6522873
+ * @summary Test that the VM don't allow random junk characters at the end of valid command line flags.
+ * @library /testlibrary
+ * @run driver TestNullTerminatedFlags
+ */
+public class TestNullTerminatedFlags {
+ public static String[] options = {
+ "-Xnoclassgc",
+ "-Xconcgc",
+ "-Xnoconcgc",
+ "-Xbatch",
+ "-green",
+ "-native",
+ "-Xsqnopause",
+ "-Xrs",
+ "-Xusealtsigs",
+ "-Xoptimize",
+ "-Xprof",
+ "-Xconcurrentio",
+ "-Xinternalversion",
+ "-Xprintflags",
+ "-Xint",
+ "-Xmixed",
+ "-Xcomp",
+ "-Xshare:dump",
+ "-Xshare:on",
+ "-Xshare:auto",
+ "-Xshare:off",
+ "-Xdebug",
+ "-Xnoagent",
+ "-Xboundthreads"
+ };
+
+ public static void main(String args[]) throws Exception{
+ for (String option : options) {
+ String testOption = option + "junk";
+ ProcessBuilder pb =
+ ProcessTools.createJavaProcessBuilder(testOption, "-version");
+ new OutputAnalyzer(pb.start())
+ .shouldContain("Unrecognized option: " + testOption)
+ .shouldHaveExitValue(1);
+ }
+ }
+}
+
--- a/hotspot/test/runtime/CompressedOops/UseCompressedOops.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/runtime/CompressedOops/UseCompressedOops.java Fri Jan 16 12:33:47 2015 -0800
@@ -35,20 +35,42 @@
public class UseCompressedOops {
public static void main(String[] args) throws Exception {
+ testCompressedOopsModesGCs();
+ testCompressedOopsModesGCs("-XX:+UseLargePages");
+ }
+
+ public static void testCompressedOopsModesGCs(String... flags) throws Exception {
+ ArrayList<String> args = new ArrayList<>();
+ Collections.addAll(args, flags);
+
+ // Test default.
+ testCompressedOopsModes(args);
+ // Test GCs.
+ testCompressedOopsModes(args, "-XX:+UseG1GC");
+ testCompressedOopsModes(args, "-XX:+UseConcMarkSweepGC");
+ testCompressedOopsModes(args, "-XX:+UseSerialGC");
+ testCompressedOopsModes(args, "-XX:+UseParallelGC");
+ testCompressedOopsModes(args, "-XX:+UseParallelOldGC");
+ }
+
+ public static void testCompressedOopsModes(ArrayList<String> flags1, String... flags2) throws Exception {
+ ArrayList<String> args = new ArrayList<>();
+ args.addAll(flags1);
+ Collections.addAll(args, flags2);
if (Platform.is64bit()) {
// Explicitly turn of compressed oops
- testCompressedOops("-XX:-UseCompressedOops", "-Xmx32m")
+ testCompressedOops(args, "-XX:-UseCompressedOops", "-Xmx32m")
.shouldNotContain("Compressed Oops")
.shouldHaveExitValue(0);
// Compressed oops should be on by default
- testCompressedOops("-Xmx32m")
+ testCompressedOops(args, "-Xmx32m")
.shouldContain("Compressed Oops mode")
.shouldHaveExitValue(0);
// Explicly enabling compressed oops
- testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m")
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32m")
.shouldContain("Compressed Oops mode")
.shouldHaveExitValue(0);
@@ -58,68 +80,89 @@
// puts the heap way up, forcing different behaviour.
if (!Platform.isOSX() && !Platform.isSolaris()) {
// Larger than 4gb heap should result in zero based with shift 3
- testCompressedOops("-XX:+UseCompressedOops", "-Xmx5g")
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx5g")
+ .shouldContain("Zero based")
+ .shouldContain("Oop shift amount: 3")
+ .shouldHaveExitValue(0);
+
+ // Larger than 3gb heap and HeapBaseMinAddress=1g should result in zero based with shift 3
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx3200m", "-XX:HeapBaseMinAddress=1g")
.shouldContain("Zero based")
.shouldContain("Oop shift amount: 3")
.shouldHaveExitValue(0);
// Small heap above 4gb should result in zero based with shift 3
- testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=4g")
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=4g")
.shouldContain("Zero based")
.shouldContain("Oop shift amount: 3")
.shouldHaveExitValue(0);
// Small heap above 32gb should result in non-zero based with shift 3
- testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=32g")
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=32g")
+ .shouldContain("Non-zero disjoint base")
+ .shouldContain("Oop shift amount: 3")
+ .shouldHaveExitValue(0);
+
+ // Small heap above 32gb should result in non-zero based with shift 3
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32m", "-XX:HeapBaseMinAddress=72704m")
.shouldContain("Non-zero based")
.shouldContain("Oop shift amount: 3")
.shouldHaveExitValue(0);
// 32gb heap with heap base above 64gb and object alignment set to 16 bytes should result
// in non-zero based with shift 4
- testCompressedOops("-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=16",
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=16",
"-XX:HeapBaseMinAddress=64g")
- .shouldContain("Non-zero based")
+ .shouldContain("Non-zero disjoint base")
.shouldContain("Oop shift amount: 4")
.shouldHaveExitValue(0);
// 32gb heap with object alignment set to 16 bytes should result in zero based with shift 4
- testCompressedOops("-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=16")
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=16")
.shouldContain("Zero based")
.shouldContain("Oop shift amount: 4")
.shouldHaveExitValue(0);
}
+ // This is a pathologic case for the heap allocation algorithm. Regression test.
+ // HeapBaseMinAddress must be 2g and should not be set on the command line.
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx2g")
+ .shouldNotContain("Max heap size too large for Compressed Oops")
+ .shouldHaveExitValue(0);
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx29g", "-XX:CompressedClassSpaceSize=1g")
+ .shouldNotContain("Max heap size too large for Compressed Oops")
+ .shouldHaveExitValue(0);
+
// Explicitly enabling compressed oops with 32gb heap should result a warning
- testCompressedOops("-XX:+UseCompressedOops", "-Xmx32g")
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32g")
.shouldContain("Max heap size too large for Compressed Oops")
.shouldHaveExitValue(0);
// 32gb heap should not result a warning
- testCompressedOops("-Xmx32g")
+ testCompressedOops(args, "-Xmx32g")
.shouldNotContain("Max heap size too large for Compressed Oops")
.shouldHaveExitValue(0);
// Explicitly enabling compressed oops with 32gb heap and object
// alignment set to 8 byte should result a warning
- testCompressedOops("-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=8")
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32g", "-XX:ObjectAlignmentInBytes=8")
.shouldContain("Max heap size too large for Compressed Oops")
.shouldHaveExitValue(0);
// 64gb heap and object alignment set to 16 bytes should result in a warning
- testCompressedOops("-XX:+UseCompressedOops", "-Xmx64g", "-XX:ObjectAlignmentInBytes=16")
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx64g", "-XX:ObjectAlignmentInBytes=16")
.shouldContain("Max heap size too large for Compressed Oops")
.shouldHaveExitValue(0);
} else {
// Compressed oops should only apply to 64bit platforms
- testCompressedOops("-XX:+UseCompressedOops", "-Xmx32m")
+ testCompressedOops(args, "-XX:+UseCompressedOops", "-Xmx32m")
.shouldContain("Unrecognized VM option 'UseCompressedOops'")
.shouldHaveExitValue(1);
}
}
- private static OutputAnalyzer testCompressedOops(String... flags) throws Exception {
+ private static OutputAnalyzer testCompressedOops(ArrayList<String> flags1, String... flags2) throws Exception {
ArrayList<String> args = new ArrayList<>();
// Always run with these three:
@@ -128,7 +171,8 @@
args.add("-Xms32m");
// Add the extra flags
- Collections.addAll(args, flags);
+ args.addAll(flags1);
+ Collections.addAll(args, flags2);
args.add("-version");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/DumpSymbolAndStringTable.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * @test
+ * @bug 8059510
+ * @summary Test jcmd VM.symboltable and VM.stringtable options
+ * @library /testlibrary
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions DumpSymbolAndStringTable
+ */
+
+import com.oracle.java.testlibrary.*;
+
+public class DumpSymbolAndStringTable {
+ public static void main(String[] args) throws Exception {
+ // Grab my own PID
+ String pid = Integer.toString(ProcessTools.getProcessId());
+
+ ProcessBuilder pb = new ProcessBuilder();
+ pb.command(new String[] {JDKToolFinder.getJDKTool("jcmd"), pid, "VM.symboltable", "-verbose"});
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ try {
+ output.shouldContain("24 2: DumpSymbolAndStringTable\n");
+ } catch (RuntimeException e) {
+ output.shouldContain("Unknown diagnostic command");
+ }
+
+ pb.command(new String[] {JDKToolFinder.getJDKTool("jcmd"), pid, "VM.stringtable", "-verbose"});
+ output = new OutputAnalyzer(pb.start());
+ try {
+ output.shouldContain("16: java.lang.String\n");
+ } catch (RuntimeException e) {
+ output.shouldContain("Unknown diagnostic command");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/SharedSymbolTableBucketSize.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8059510
+ * @summary Test SharedSymbolTableBucketSize option
+ * @library /testlibrary
+ */
+
+import com.oracle.java.testlibrary.*;
+
+public class SharedSymbolTableBucketSize {
+ public static void main(String[] args) throws Exception {
+ int bucket_size = 8;
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-Xshare:dump", "-XX:+PrintSharedSpaces",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:SharedArchiveFile=./sample.jsa",
+ "-XX:SharedSymbolTableBucketSize=" + Integer.valueOf(bucket_size));
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldContain("Loading classes to share");
+ output.shouldHaveExitValue(0);
+
+ String s = output.firstMatch("Average bucket size : .*");
+ Float f = Float.parseFloat(s.substring(25));
+ int size = Math.round(f);
+ if (size != bucket_size) {
+ throw new Exception("FAILED: incorrect bucket size " + size +
+ ", expect " + bucket_size);
+ }
+
+
+ // Invalid SharedSymbolTableBucketSize input
+ String input[] = {"-XX:SharedSymbolTableBucketSize=-1",
+ "-XX:SharedSymbolTableBucketSize=2.5"};
+ for (int i = 0; i < input.length; i++) {
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-Xshare:dump", "-XX:+PrintSharedSpaces",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:SharedArchiveFile=./sample.jsa",
+ input[i]);
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("Improperly specified VM option");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/stress/gc/TestGCOld.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,417 @@
+/*
+* 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 TestGCOld
+ * @key gc
+ * @key stress
+ * @requires vm.gc=="null"
+ * @summary Stress the GC by trying to make old objects more likely to be garbage than young objects.
+ * @run main/othervm -Xmx384M -XX:+UseSerialGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseParallelGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseParallelGC -XX:-UseParallelOldGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseConcMarkSweepGC TestGCOld 50 1 20 10 10000
+ * @run main/othervm -Xmx384M -XX:+UseG1GC TestGCOld 50 1 20 10 10000
+ */
+
+import java.text.*;
+import java.util.Random;
+
+class TreeNode {
+ public TreeNode left, right;
+ public int val; // will always be the height of the tree
+}
+
+
+/* Args:
+ live-data-size: in megabytes (approximate, will be rounded down).
+ work: units of mutator non-allocation work per byte allocated,
+ (in unspecified units. This will affect the promotion rate
+ printed at the end of the run: more mutator work per step implies
+ fewer steps per second implies fewer bytes promoted per second.)
+ short/long ratio: ratio of short-lived bytes allocated to long-lived
+ bytes allocated.
+ pointer mutation rate: number of pointer mutations per step.
+ steps: number of steps to do.
+*/
+
+public class TestGCOld {
+
+ // Command-line parameters.
+
+ private static int size, workUnits, promoteRate, ptrMutRate, steps;
+
+ // Constants.
+
+ private static final int MEG = 1000000;
+ private static final int INSIGNIFICANT = 999; // this many bytes don't matter
+ private static final int BYTES_PER_WORD = 4;
+ private static final int BYTES_PER_NODE = 20; // bytes per TreeNode
+ private static final int WORDS_DEAD = 100; // size of young garbage object
+
+ private final static int treeHeight = 14;
+ private final static long treeSize = heightToBytes(treeHeight);
+
+ private static final String msg1
+ = "Usage: java TestGCOld <size> <work> <ratio> <mutation> <steps>";
+ private static final String msg2
+ = " where <size> is the live storage in megabytes";
+ private static final String msg3
+ = " <work> is the mutator work per step (arbitrary units)";
+ private static final String msg4
+ = " <ratio> is the ratio of short-lived to long-lived allocation";
+ private static final String msg5
+ = " <mutation> is the mutations per step";
+ private static final String msg6
+ = " <steps> is the number of steps";
+
+ // Counters (and global variables that discourage optimization)
+
+ private static long youngBytes = 0; // total young bytes allocated
+ private static long nodes = 0; // total tree nodes allocated
+ private static long actuallyMut = 0; // pointer mutations in old trees
+ private static long mutatorSum = 0; // checksum to discourage optimization
+ public static int[] aexport; // exported array to discourage opt
+
+ // Global variables.
+
+ private static TreeNode[] trees;
+ private static int where = 0; // roving index into trees
+ private static Random rnd = new Random();
+
+ // Returns the height of the given tree.
+
+ private static int height (TreeNode t) {
+ if (t == null) {
+ return 0;
+ }
+ else {
+ return 1 + Math.max (height (t.left), height (t.right));
+ }
+ }
+
+ // Returns the length of the shortest path in the given tree.
+
+ private static int shortestPath (TreeNode t) {
+ if (t == null) {
+ return 0;
+ }
+ else {
+ return 1 + Math.min (shortestPath (t.left), shortestPath (t.right));
+ }
+ }
+
+ // Returns the number of nodes in a balanced tree of the given height.
+
+ private static long heightToNodes (int h) {
+ if (h == 0) {
+ return 0;
+ }
+ else {
+ long n = 1;
+ while (h > 1) {
+ n = n + n;
+ h = h - 1;
+ }
+ return n + n - 1;
+ }
+ }
+
+ // Returns the number of bytes in a balanced tree of the given height.
+
+ private static long heightToBytes (int h) {
+ return BYTES_PER_NODE * heightToNodes (h);
+ }
+
+ // Returns the height of the largest balanced tree
+ // that has no more than the given number of nodes.
+
+ private static int nodesToHeight (long nodes) {
+ int h = 1;
+ long n = 1;
+ while (n + n - 1 <= nodes) {
+ n = n + n;
+ h = h + 1;
+ }
+ return h - 1;
+ }
+
+ // Returns the height of the largest balanced tree
+ // that occupies no more than the given number of bytes.
+
+ private static int bytesToHeight (long bytes) {
+ return nodesToHeight (bytes / BYTES_PER_NODE);
+ }
+
+ // Returns a newly allocated balanced binary tree of height h.
+
+ private static TreeNode makeTree(int h) {
+ if (h == 0) return null;
+ else {
+ TreeNode res = new TreeNode();
+ nodes++;
+ res.left = makeTree(h-1);
+ res.right = makeTree(h-1);
+ res.val = h;
+ return res;
+ }
+ }
+
+ // Allocates approximately size megabytes of trees and stores
+ // them into a global array.
+
+ private static void init() {
+ int ntrees = (int) ((size * MEG) / treeSize);
+ trees = new TreeNode[ntrees];
+
+ System.err.println("Allocating " + ntrees + " trees.");
+ System.err.println(" (" + (ntrees * treeSize) + " bytes)");
+ for (int i = 0; i < ntrees; i++) {
+ trees[i] = makeTree(treeHeight);
+ // doYoungGenAlloc(promoteRate*ntrees*treeSize, WORDS_DEAD);
+ }
+ System.err.println(" (" + nodes + " nodes)");
+
+ /* Allow any in-progress GC to catch up... */
+ // try { Thread.sleep(20000); } catch (InterruptedException x) {}
+ }
+
+ // Confirms that all trees are balanced and have the correct height.
+
+ private static void checkTrees() {
+ int ntrees = trees.length;
+ for (int i = 0; i < ntrees; i++) {
+ TreeNode t = trees[i];
+ int h1 = height(t);
+ int h2 = shortestPath(t);
+ if ((h1 != treeHeight) || (h2 != treeHeight)) {
+ System.err.println("*****BUG: " + h1 + " " + h2);
+ }
+ }
+ }
+
+ // Called only by replaceTree (below) and by itself.
+
+ private static void replaceTreeWork(TreeNode full, TreeNode partial, boolean dir) {
+ boolean canGoLeft = full.left != null && full.left.val > partial.val;
+ boolean canGoRight = full.right != null && full.right.val > partial.val;
+ if (canGoLeft && canGoRight) {
+ if (dir)
+ replaceTreeWork(full.left, partial, !dir);
+ else
+ replaceTreeWork(full.right, partial, !dir);
+ } else if (!canGoLeft && !canGoRight) {
+ if (dir)
+ full.left = partial;
+ else
+ full.right = partial;
+ } else if (!canGoLeft) {
+ full.left = partial;
+ } else {
+ full.right = partial;
+ }
+ }
+
+ // Given a balanced tree full and a smaller balanced tree partial,
+ // replaces an appropriate subtree of full by partial, taking care
+ // to preserve the shape of the full tree.
+
+ private static void replaceTree(TreeNode full, TreeNode partial) {
+ boolean dir = (partial.val % 2) == 0;
+ actuallyMut++;
+ replaceTreeWork(full, partial, dir);
+ }
+
+ // Allocates approximately n bytes of long-lived storage,
+ // replacing oldest existing long-lived storage.
+
+ private static void oldGenAlloc(long n) {
+ int full = (int) (n / treeSize);
+ long partial = n % treeSize;
+ // System.out.println("In oldGenAlloc, doing " + full + " full trees "
+ // + "and one partial tree of size " + partial);
+ for (int i = 0; i < full; i++) {
+ trees[where++] = makeTree(treeHeight);
+ if (where == trees.length) where = 0;
+ }
+ while (partial > INSIGNIFICANT) {
+ int h = bytesToHeight(partial);
+ TreeNode newTree = makeTree(h);
+ replaceTree(trees[where++], newTree);
+ if (where == trees.length) where = 0;
+ partial = partial - heightToBytes(h);
+ }
+ }
+
+ // Interchanges two randomly selected subtrees (of same size and depth).
+
+ private static void oldGenSwapSubtrees() {
+ // Randomly pick:
+ // * two tree indices
+ // * A depth
+ // * A path to that depth.
+ int index1 = rnd.nextInt(trees.length);
+ int index2 = rnd.nextInt(trees.length);
+ int depth = rnd.nextInt(treeHeight);
+ int path = rnd.nextInt();
+ TreeNode tn1 = trees[index1];
+ TreeNode tn2 = trees[index2];
+ for (int i = 0; i < depth; i++) {
+ if ((path & 1) == 0) {
+ tn1 = tn1.left;
+ tn2 = tn2.left;
+ } else {
+ tn1 = tn1.right;
+ tn2 = tn2.right;
+ }
+ path >>= 1;
+ }
+ TreeNode tmp;
+ if ((path & 1) == 0) {
+ tmp = tn1.left;
+ tn1.left = tn2.left;
+ tn2.left = tmp;
+ } else {
+ tmp = tn1.right;
+ tn1.right = tn2.right;
+ tn2.right = tmp;
+ }
+ actuallyMut += 2;
+ }
+
+ // Update "n" old-generation pointers.
+
+ private static void oldGenMut(long n) {
+ for (int i = 0; i < n/2; i++) {
+ oldGenSwapSubtrees();
+ }
+ }
+
+ // Does the amount of mutator work appropriate for n bytes of young-gen
+ // garbage allocation.
+
+ private static void doMutWork(long n) {
+ int sum = 0;
+ long limit = workUnits*n/10;
+ for (long k = 0; k < limit; k++) sum++;
+ // We don't want dead code elimination to eliminate the loop above.
+ mutatorSum = mutatorSum + sum;
+ }
+
+ // Allocate n bytes of young-gen garbage, in units of "nwords"
+ // words.
+
+ private static void doYoungGenAlloc(long n, int nwords) {
+ final int nbytes = nwords*BYTES_PER_WORD;
+ int allocated = 0;
+ while (allocated < n) {
+ aexport = new int[nwords];
+ /* System.err.println("Step"); */
+ allocated += nbytes;
+ }
+ youngBytes = youngBytes + allocated;
+ }
+
+ // Allocate "n" bytes of young-gen data; and do the
+ // corresponding amount of old-gen allocation and pointer
+ // mutation.
+
+ // oldGenAlloc may perform some mutations, so this code
+ // takes those mutations into account.
+
+ private static void doStep(long n) {
+ long mutations = actuallyMut;
+
+ doYoungGenAlloc(n, WORDS_DEAD);
+ doMutWork(n);
+ oldGenAlloc(n / promoteRate);
+ oldGenMut(Math.max(0L, (mutations + ptrMutRate) - actuallyMut));
+ }
+
+ public static void main(String[] args) {
+ if (args.length != 5) {
+ System.err.println(msg1);
+ System.err.println(msg2);
+ System.err.println(msg3);
+ System.err.println(msg4);
+ System.err.println(msg5);
+ System.err.println(msg6);
+ return;
+ }
+
+ size = Integer.parseInt(args[0]);
+ workUnits = Integer.parseInt(args[1]);
+ promoteRate = Integer.parseInt(args[2]);
+ ptrMutRate = Integer.parseInt(args[3]);
+ steps = Integer.parseInt(args[4]);
+
+ System.out.println(size + " megabytes of live storage");
+ System.out.println(workUnits + " work units per step");
+ System.out.println("promotion ratio is 1:" + promoteRate);
+ System.out.println("pointer mutation rate is " + ptrMutRate);
+ System.out.println(steps + " steps");
+
+ init();
+// checkTrees();
+ youngBytes = 0;
+ nodes = 0;
+
+ System.err.println("Initialization complete...");
+
+ long start = System.currentTimeMillis();
+
+ for (int step = 0; step < steps; step++) {
+ doStep(MEG);
+ }
+
+ long end = System.currentTimeMillis();
+ float secs = ((float)(end-start))/1000.0F;
+
+// checkTrees();
+
+ NumberFormat nf = NumberFormat.getInstance();
+ nf.setMaximumFractionDigits(1);
+ System.out.println("\nTook " + nf.format(secs) + " sec in steady state.");
+ nf.setMaximumFractionDigits(2);
+ System.out.println("Allocated " + steps + " Mb of young gen garbage"
+ + " (= " + nf.format(((float)steps)/secs) +
+ " Mb/sec)");
+ System.out.println(" (actually allocated " +
+ nf.format(((float) youngBytes)/MEG) + " megabytes)");
+ float promoted = ((float)steps) / (float)promoteRate;
+ System.out.println("Promoted " + promoted +
+ " Mb (= " + nf.format(promoted/secs) + " Mb/sec)");
+ System.out.println(" (actually promoted " +
+ nf.format(((float) (nodes * BYTES_PER_NODE))/MEG) +
+ " megabytes)");
+ if (ptrMutRate != 0) {
+ System.out.println("Mutated " + actuallyMut +
+ " pointers (= " +
+ nf.format(actuallyMut/secs) + " ptrs/sec)");
+
+ }
+ // This output serves mainly to discourage optimization.
+ System.out.println("Checksum = " + (mutatorSum + aexport.length));
+
+ }
+}
--- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/ByteCodeLoader.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ByteCodeLoader.java Fri Jan 16 12:33:47 2015 -0800
@@ -37,6 +37,7 @@
public class ByteCodeLoader extends SecureClassLoader {
private final String className;
private final byte[] byteCode;
+ private volatile Class<?> holder;
/**
* Creates a new {@code ByteCodeLoader} ready to load a class with the
@@ -51,6 +52,21 @@
}
@Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ if (!name.equals(className)) {
+ return super.loadClass(name);
+ }
+ if (holder == null) {
+ synchronized(this) {
+ if (holder == null) {
+ holder = findClass(name);
+ }
+ }
+ }
+ return holder;
+ }
+
+ @Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (!name.equals(className)) {
throw new ClassNotFoundException(name);
--- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/InfiniteLoop.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/InfiniteLoop.java Fri Jan 16 12:33:47 2015 -0800
@@ -54,7 +54,9 @@
try {
while (true) {
target.run();
- Thread.sleep(mills);
+ if (mills > 0) {
+ Thread.sleep(mills);
+ }
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
--- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Platform.java Fri Jan 16 12:33:47 2015 -0800
@@ -34,6 +34,7 @@
private static final String osArch = System.getProperty("os.arch");
private static final String vmName = System.getProperty("java.vm.name");
private static final String userName = System.getProperty("user.name");
+ private static final String compiler = System.getProperty("sun.management.compiler");
public static boolean isClient() {
return vmName.endsWith(" Client VM");
@@ -55,6 +56,10 @@
return vmName.contains("Embedded");
}
+ public static boolean isTieredSupported() {
+ return compiler.contains("Tiered Compilers");
+ }
+
public static boolean is32bit() {
return dataModel.equals("32");
}
--- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Utils.java Fri Jan 16 12:33:47 2015 -0800
@@ -40,6 +40,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Random;
+import java.util.function.BooleanSupplier;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -306,25 +307,6 @@
}
/**
- * Returns file content as a list of strings
- *
- * @param file File to operate on
- * @return List of strings
- * @throws IOException
- */
- public static List<String> fileAsList(File file) throws IOException {
- assertTrue(file.exists() && file.isFile(),
- file.getAbsolutePath() + " does not exist or not a file");
- List<String> output = new ArrayList<>();
- try (BufferedReader reader = new BufferedReader(new FileReader(file.getAbsolutePath()))) {
- while (reader.ready()) {
- output.add(reader.readLine().replace(NEW_LINE, ""));
- }
- }
- return output;
- }
-
- /**
* Return the contents of the named file as a single String,
* or null if not found.
* @param filename name of the file to read
@@ -396,6 +378,52 @@
}
/**
+ * Wait for condition to be true
+ *
+ * @param condition, a condition to wait for
+ */
+ public static final void waitForCondition(BooleanSupplier condition) {
+ waitForCondition(condition, -1L, 100L);
+ }
+
+ /**
+ * Wait until timeout for condition to be true
+ *
+ * @param condition, a condition to wait for
+ * @param timeout a time in milliseconds to wait for condition to be true
+ * specifying -1 will wait forever
+ * @return condition value, to determine if wait was successfull
+ */
+ public static final boolean waitForCondition(BooleanSupplier condition,
+ long timeout) {
+ return waitForCondition(condition, timeout, 100L);
+ }
+
+ /**
+ * Wait until timeout for condition to be true for specified time
+ *
+ * @param condition, a condition to wait for
+ * @param timeout a time in milliseconds to wait for condition to be true,
+ * specifying -1 will wait forever
+ * @param sleepTime a time to sleep value in milliseconds
+ * @return condition value, to determine if wait was successfull
+ */
+ public static final boolean waitForCondition(BooleanSupplier condition,
+ long timeout, long sleepTime) {
+ long startTime = System.currentTimeMillis();
+ while (!(condition.getAsBoolean() || (timeout != -1L
+ && ((System.currentTimeMillis() - startTime) > timeout)))) {
+ try {
+ Thread.sleep(sleepTime);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new Error(e);
+ }
+ }
+ return condition.getAsBoolean();
+ }
+
+ /**
* Adjusts the provided timeout value for the TIMEOUT_FACTOR
* @param tOut the timeout value to be adjusted
* @return The timeout value adjusted for the value of "test.timeout.factor"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dtrace/DtraceResultsAnalyzer.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.java.testlibrary.dtrace;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public interface DtraceResultsAnalyzer {
+ public void analyze(OutputAnalyzer oa, String logFilePath);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dtrace/DtraceRunner.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.java.testlibrary.dtrace;
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DtraceRunner {
+
+ private static final String DTRACE_DEFAULT_PATH = "/usr/sbin/dtrace";
+ private static final String DTRACE_PATH_PROPERTY
+ = "com.oracle.test.dtrace.path";
+ private static final String OUTPUT_FILE_DTRACE_OPTION = "o";
+ private static final String RUN_COMMAND_DTRACE_OPTION = "c";
+ private static final String RUN_SCRIPT_DTRACE_OPTION = "s";
+ private static final String ALLOW_ZERO_PROBE_DESCRIPTION_DTRACE_OPTION = "Z";
+ private static final String DTRACE_OPTION_PREFIX = "-";
+ public static final String PERMIT_DESTRUCTIVE_ACTIONS_DTRACE_OPTION = "w";
+ public static final String DTRACE_OUT_LOG = "dtrace.out";
+
+ private final String dtraceExecutable;
+
+ public DtraceRunner() {
+ dtraceExecutable = getDtracePath();
+ }
+
+ private List<String> getLaunchCmd(String java, String javaOpts,
+ String execClass, String testArgs, String dtraceScript,
+ String dtraceAddOpts) {
+ Asserts.assertTrue(!java.matches("\\s"), "Current dtrace implementation"
+ + " can't handle whitespaces in application path");
+ List<String> result = new ArrayList<>();
+ result.add(dtraceExecutable);
+ result.add(DTRACE_OPTION_PREFIX + System.getProperty("sun.arch.data.model"));
+ result.add(DTRACE_OPTION_PREFIX
+ + ALLOW_ZERO_PROBE_DESCRIPTION_DTRACE_OPTION
+ + ((dtraceAddOpts == null) ? "" : dtraceAddOpts)
+ + RUN_SCRIPT_DTRACE_OPTION); // run_script should be last one
+ result.add(dtraceScript);
+ result.add(DTRACE_OPTION_PREFIX + OUTPUT_FILE_DTRACE_OPTION);
+ result.add(DTRACE_OUT_LOG);
+ result.add(DTRACE_OPTION_PREFIX + RUN_COMMAND_DTRACE_OPTION);
+ result.add(java + " " + javaOpts + " " + execClass + " " + testArgs);
+ return result;
+ }
+
+ private void backupLogFile(File file) {
+ if (file.exists()) {
+ file.renameTo(new File(file.getPath() + ".bak"));
+ }
+ }
+
+ public void runDtrace(String java, String javaOpts, String execClass,
+ String testArgs, String dtraceScript, String dtraceAddOpts,
+ DtraceResultsAnalyzer analyzer) {
+ backupLogFile(new File(DTRACE_OUT_LOG));
+ ProcessBuilder pbuilder = new ProcessBuilder(
+ getLaunchCmd(java, javaOpts, execClass, testArgs,
+ dtraceScript, dtraceAddOpts));
+ OutputAnalyzer oa;
+ try {
+ oa = new OutputAnalyzer(pbuilder.start());
+ } catch (IOException e) {
+ throw new Error("TESTBUG: Can't start process", e);
+ }
+ analyzer.analyze(oa, DTRACE_OUT_LOG);
+ }
+
+ public static boolean dtraceAvailable() {
+ String path = getDtracePath();
+ if (path == null) {
+ return false;
+ }
+ // now we'll launch dtrace to trace itself just to be sure it works
+ // and have all additional previleges set
+ ProcessBuilder pbuilder = new ProcessBuilder(path, path);
+ try {
+ OutputAnalyzer oa = new OutputAnalyzer(pbuilder.start());
+ if (oa.getExitValue() != 0) {
+ return false;
+ }
+ } catch (IOException e) {
+ throw new Error("Couldn't launch dtrace", e);
+ }
+ return true;
+ }
+
+ private static String getDtracePath() {
+ String propPath = System.getProperty(DTRACE_PATH_PROPERTY);
+ if (propPath != null && new File(propPath).exists()) {
+ return propPath;
+ } else if (new File(DTRACE_DEFAULT_PATH).exists()) {
+ return DTRACE_DEFAULT_PATH;
+ }
+ return null;
+ }
+}
--- a/hotspot/test/testlibrary/ctw/test/Bar.java Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-public class Bar {
- private static void staticMethod() { }
- public void method() { }
- protected Bar() { }
-}
--- a/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8012447
- * @library /testlibrary /../../test/lib /testlibrary/ctw/src
- * @build ClassFileInstaller sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar
- * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
- * sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main ClassesDirTest prepare
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes
- * @run main ClassesDirTest check ctw.log
- * @summary testing of CompileTheWorld :: classes in directory
- * @author igor.ignatyev@oracle.com
- */
-
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-
-public class ClassesDirTest extends CtwTest {
- private static final String[] SHOULD_CONTAIN
- = {"# dir: classes", "Done (2 classes, 6 methods, "};
-
- private ClassesDirTest() {
- super(SHOULD_CONTAIN);
- }
-
- public static void main(String[] args) throws Exception {
- new ClassesDirTest().run(args);
- }
-
- protected void prepare() throws Exception {
- String path = "classes";
- Files.createDirectory(Paths.get(path));
- Files.move(Paths.get("Foo.class"), Paths.get(path, "Foo.class"),
- StandardCopyOption.REPLACE_EXISTING);
- Files.move(Paths.get("Bar.class"), Paths.get(path, "Bar.class"),
- StandardCopyOption.REPLACE_EXISTING);
- }
-}
--- a/hotspot/test/testlibrary/ctw/test/ClassesListTest.java Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8012447
- * @library /testlibrary /../../test/lib /testlibrary/ctw/src
- * @build ClassFileInstaller sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar
- * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
- * sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main ClassesListTest prepare
- * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst
- * @run main ClassesListTest check ctw.log
- * @summary testing of CompileTheWorld :: list of classes in file
- * @author igor.ignatyev@oracle.com
- */
-
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-
-public class ClassesListTest extends CtwTest {
- private static final String[] SHOULD_CONTAIN
- = {"# list: classes.lst", "Done (4 classes, "};
-
- private ClassesListTest() {
- super(SHOULD_CONTAIN);
- }
-
- public static void main(String[] args) throws Exception {
- new ClassesListTest().run(args);
- }
-
- protected void prepare() throws Exception {
- String path = "classes.lst";
- Files.copy(Paths.get(System.getProperty("test.src"), path),
- Paths.get(path), StandardCopyOption.REPLACE_EXISTING);
- }
-}
--- a/hotspot/test/testlibrary/ctw/test/CtwTest.java Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.util.List;
-import java.util.Collections;
-import java.util.ArrayList;
-
-import java.io.File;
-import java.io.Writer;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.BufferedReader;
-
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.nio.charset.Charset;
-
-import com.oracle.java.testlibrary.JDKToolFinder;
-import com.oracle.java.testlibrary.OutputAnalyzer;
-
-public abstract class CtwTest {
- protected final String[] shouldContain;
- protected CtwTest(String[] shouldContain) {
- this.shouldContain = shouldContain;
- }
-
- public void run(String[] args) throws Exception {
- if (args.length == 0) {
- throw new Error("args is empty");
- }
- switch (args[0]) {
- case "prepare":
- prepare();
- break;
- case "check":
- check(args);
- break;
- default:
- throw new Error("unregonized action -- " + args[0]);
- }
- }
-
- protected void prepare() throws Exception { }
-
- protected void check(String[] args) throws Exception {
- if (args.length < 2) {
- throw new Error("logfile isn't specified");
- }
- String logfile = args[1];
- try (BufferedReader r = Files.newBufferedReader(Paths.get(logfile),
- Charset.defaultCharset())) {
- OutputAnalyzer output = readOutput(r);
- for (String test : shouldContain) {
- output.shouldContain(test);
- }
- }
- }
-
- private static OutputAnalyzer readOutput(BufferedReader reader)
- throws IOException {
- StringBuilder builder = new StringBuilder();
- String eol = String.format("%n");
- String line;
-
- while ((line = reader.readLine()) != null) {
- builder.append(line);
- builder.append(eol);
- }
- return new OutputAnalyzer(builder.toString(), "");
- }
-
- protected void dump(OutputAnalyzer output, String name) {
- try (Writer w = new FileWriter(name + ".out")) {
- String s = output.getStdout();
- w.write(s, s.length(), 0);
- } catch (IOException io) {
- io.printStackTrace();
- }
- try (Writer w = new FileWriter(name + ".err")) {
- String s = output.getStderr();
- w.write(s, s.length(), 0);
- } catch (IOException io) {
- io.printStackTrace();
- }
- }
-
- protected ProcessBuilder createJarProcessBuilder(String... command)
- throws Exception {
- String javapath = JDKToolFinder.getJDKTool("jar");
-
- ArrayList<String> args = new ArrayList<>();
- args.add(javapath);
- Collections.addAll(args, command);
-
- return new ProcessBuilder(args.toArray(new String[args.size()]));
- }
-}
--- a/hotspot/test/testlibrary/ctw/test/Foo.java Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-public class Foo {
- private static void staticMethod() { }
- public void method() { }
- protected Foo() { }
-}
--- a/hotspot/test/testlibrary/ctw/test/JarDirTest.java Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8012447
- * @library /testlibrary /../../test/lib /testlibrary/ctw/src
- * @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar
- * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
- * sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main JarDirTest prepare
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/*
- * @run main JarDirTest check ctw.log
- * @summary testing of CompileTheWorld :: jars in directory
- * @author igor.ignatyev@oracle.com
- */
-
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-
-import com.oracle.java.testlibrary.OutputAnalyzer;
-
-public class JarDirTest extends CtwTest {
- private static final String[] SHOULD_CONTAIN
- = {"# jar_in_dir: jars",
- "# jar: jars" + File.separator +"foo.jar",
- "# jar: jars" + File.separator +"bar.jar",
- "Done (4 classes, 12 methods, "};
-
- private JarDirTest() {
- super(SHOULD_CONTAIN);
- }
-
- public static void main(String[] args) throws Exception {
- new JarDirTest().run(args);
- }
-
- protected void prepare() throws Exception {
- String path = "jars";
- Files.createDirectory(Paths.get(path));
-
- ProcessBuilder pb = createJarProcessBuilder("cf", "jars/foo.jar",
- "Foo.class", "Bar.class");
- OutputAnalyzer output = new OutputAnalyzer(pb.start());
- dump(output, "ctw-foo.jar");
- output.shouldHaveExitValue(0);
-
- pb = createJarProcessBuilder("cf", "jars/bar.jar", "Foo.class",
- "Bar.class");
- output = new OutputAnalyzer(pb.start());
- dump(output, "ctw-bar.jar");
- output.shouldHaveExitValue(0);
- }
-
-}
--- a/hotspot/test/testlibrary/ctw/test/JarsTest.java Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8012447
- * @library /testlibrary /../../test/lib /testlibrary/ctw/src
- * @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox Foo Bar
- * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
- * sun.hotspot.WhiteBox$WhiteBoxPermission
- * @run main JarsTest prepare
- * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar
- * @run main JarsTest check ctw.log
- * @summary testing of CompileTheWorld :: jars
- * @author igor.ignatyev@oracle.com
- */
-
-import com.oracle.java.testlibrary.OutputAnalyzer;
-
-public class JarsTest extends CtwTest {
- private static final String[] SHOULD_CONTAIN
- = {"# jar: foo.jar", "# jar: bar.jar",
- "Done (4 classes, 12 methods, "};
-
- private JarsTest() {
- super(SHOULD_CONTAIN);
- }
-
- public static void main(String[] args) throws Exception {
- new JarsTest().run(args);
- }
-
- protected void prepare() throws Exception {
- ProcessBuilder pb = createJarProcessBuilder("cf", "foo.jar",
- "Foo.class", "Bar.class");
- OutputAnalyzer output = new OutputAnalyzer(pb.start());
- dump(output, "ctw-foo.jar");
- output.shouldHaveExitValue(0);
-
- pb = createJarProcessBuilder("cf", "bar.jar", "Foo.class", "Bar.class");
- output = new OutputAnalyzer(pb.start());
- dump(output, "ctw-bar.jar");
- output.shouldHaveExitValue(0);
- }
-
-}
--- a/hotspot/test/testlibrary/ctw/test/classes.lst Thu Jan 15 13:09:39 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-java.lang.String
-java.lang.Object
-Foo
-Bar
--- a/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java Thu Jan 15 13:09:39 2015 -0800
+++ b/hotspot/test/testlibrary_tests/TestMutuallyExclusivePlatformPredicates.java Fri Jan 16 12:33:47 2015 -0800
@@ -48,7 +48,7 @@
OS("isLinux", "isSolaris", "isWindows", "isOSX"),
VM_TYPE("isClient", "isServer", "isGraal", "isMinimal"),
IGNORED("isEmbedded", "isDebugBuild", "shouldSAAttach",
- "canPtraceAttachLinux", "canAttachOSX");
+ "canPtraceAttachLinux", "canAttachOSX", "isTieredSupported");
public final List<String> methodNames;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary_tests/TestPlatformIsTieredSupported.java Fri Jan 16 12:33:47 2015 -0800
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.Platform;
+import sun.hotspot.WhiteBox;
+
+/**
+ * @test
+ * @summary Verifies that Platform::isTieredSupported returns correct value.
+ * @library /testlibrary /../../test/lib
+ * @build TestPlatformIsTieredSupported
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI -XX:+TieredCompilation
+ * TestPlatformIsTieredSupported
+ */
+public class TestPlatformIsTieredSupported {
+ public static void main(String args[]) {
+ WhiteBox whiteBox = WhiteBox.getWhiteBox();
+ boolean tieredCompilation = whiteBox.getBooleanVMFlag(
+ "TieredCompilation");
+ Asserts.assertEQ(Platform.isTieredSupported(), tieredCompilation,
+ "Platform::isTieredSupported should report the same value as "
+ + "TieredCompilation flag's value when "
+ + "+TieredCompilation was explicitly passed to JVM.");
+ }
+}