Merge
This commit is contained in:
commit
7c4d03b281
162
hotspot/agent/src/share/classes/sun/jvm/hotspot/SAGetopt.java
Normal file
162
hotspot/agent/src/share/classes/sun/jvm/hotspot/SAGetopt.java
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class SAGetopt {
|
||||
|
||||
private String[] _argv;
|
||||
|
||||
private int _optind; // index in arguments array
|
||||
private int _optopt; // index within an argument
|
||||
private String _optarg; // last option argument
|
||||
private boolean _optreset; // special handling of first call
|
||||
|
||||
public SAGetopt(String[] args) {
|
||||
_argv = args;
|
||||
_optind = 0;
|
||||
_optopt = 1;
|
||||
_optarg = null;
|
||||
_optreset = true;
|
||||
}
|
||||
|
||||
public String getOptarg() {
|
||||
return _optarg;
|
||||
}
|
||||
|
||||
public int getOptind() {
|
||||
return _optind;
|
||||
}
|
||||
|
||||
private void extractOptarg(String opt) {
|
||||
// Argument expected
|
||||
if (_optind > _argv.length) {
|
||||
throw new RuntimeException("Not enough arguments for '" + opt + "'");
|
||||
}
|
||||
|
||||
if (! _argv[_optind].isEmpty() && _argv[_optind].charAt(0) == '-') {
|
||||
throw new RuntimeException("Argument is expected for '" + opt + "'");
|
||||
}
|
||||
|
||||
_optarg = _argv[_optind];
|
||||
_optind += 1;
|
||||
}
|
||||
|
||||
private String processLongOptions(String carg, String[] longOptStr) {
|
||||
List<String> los = Arrays.asList(longOptStr);
|
||||
String[] ca = carg.split("=", 2);
|
||||
|
||||
if (los.contains(ca[0])) {
|
||||
if (ca.length > 1) {
|
||||
throw new RuntimeException("Argument is not expected for '" + ca[0] + "'");
|
||||
}
|
||||
return carg;
|
||||
}
|
||||
|
||||
if (los.contains(ca[0] + "=")) {
|
||||
if (ca.length > 1) {
|
||||
// GNU style options --file=name
|
||||
_optarg = ca[1];
|
||||
}
|
||||
else {
|
||||
// Mixed style options --file name
|
||||
extractOptarg(ca[0]);
|
||||
}
|
||||
|
||||
return ca[0];
|
||||
}
|
||||
|
||||
throw new RuntimeException("Invalid option '" + ca[0] + "'");
|
||||
}
|
||||
|
||||
public String next(String optStr, String[] longOptStr) {
|
||||
|
||||
if (_optind >= _argv.length || _argv[_optind] == null) {
|
||||
// All arguments processed
|
||||
return null;
|
||||
}
|
||||
|
||||
String carg = _argv[_optind];
|
||||
_optarg = null;
|
||||
|
||||
if (_optreset) {
|
||||
// End of option batch like '-abc' reached, expect option to start from '-'
|
||||
|
||||
if (carg.isEmpty() || carg.charAt(0) != '-' || carg.equals("--")) {
|
||||
// Stop processing on -- or first non-option argument;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (carg.startsWith("--")) {
|
||||
// Handle long options, it can't be combined so it's simple
|
||||
if (longOptStr == null || longOptStr.length == 0) {
|
||||
// No long options expected, stop options processing
|
||||
return null;
|
||||
}
|
||||
++ _optind;
|
||||
|
||||
// at this point carg contains at least one character besides --
|
||||
carg = carg.substring(2);
|
||||
return processLongOptions(carg, longOptStr);
|
||||
}
|
||||
|
||||
if (optStr == null || optStr.length() == 0) {
|
||||
// No short options
|
||||
return null;
|
||||
}
|
||||
|
||||
// At this point carg[0] contains '-'
|
||||
_optreset = false;
|
||||
_optopt = 1;
|
||||
}
|
||||
|
||||
char ch = carg.charAt(_optopt);
|
||||
|
||||
// adjust pointer to next character
|
||||
_optopt += 1;
|
||||
|
||||
// Okay, ready to process options like
|
||||
// -abc -d bla -ef
|
||||
|
||||
int chIndex = optStr.indexOf(ch);
|
||||
if (chIndex == -1) {
|
||||
throw new RuntimeException("Invalid option '" + ch + "'");
|
||||
}
|
||||
|
||||
if (_optopt >= carg.length()) {
|
||||
_optind += 1;
|
||||
_optreset = true;
|
||||
}
|
||||
|
||||
if (chIndex < optStr.length()-1 && optStr.charAt(chIndex+1) == ':') {
|
||||
// Argument expected
|
||||
extractOptarg(String.valueOf(ch));
|
||||
}
|
||||
|
||||
return String.valueOf(ch);
|
||||
}
|
||||
}
|
359
hotspot/agent/src/share/classes/sun/jvm/hotspot/SALauncher.java
Normal file
359
hotspot/agent/src/share/classes/sun/jvm/hotspot/SALauncher.java
Normal file
@ -0,0 +1,359 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import sun.jvm.hotspot.tools.JStack;
|
||||
import sun.jvm.hotspot.tools.JMap;
|
||||
import sun.jvm.hotspot.tools.JInfo;
|
||||
|
||||
public class SALauncher {
|
||||
|
||||
private static boolean launcherHelp() {
|
||||
System.out.println(" clhsdb \tcommand line debugger");
|
||||
System.out.println(" hsdb \tui debugger");
|
||||
System.out.println(" jstack --help\tto get more information");
|
||||
System.out.println(" jmap --help\tto get more information");
|
||||
System.out.println(" jinfo --help\tto get more information");
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean commonHelp() {
|
||||
// --pid <pid>
|
||||
// --exe <exe>
|
||||
// --core <core>
|
||||
System.out.println(" --exe\texecutable image name");
|
||||
System.out.println(" --core\tpath to coredump");
|
||||
System.out.println(" --pid\tpid of process to attach");
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean jinfoHelp() {
|
||||
// --flags -> -flags
|
||||
// --sysprops -> -sysprops
|
||||
System.out.println(" --flags\tto print VM flags");
|
||||
System.out.println(" --sysprops\tto print Java System properties");
|
||||
System.out.println(" <no option>\tto print both of the above");
|
||||
return commonHelp();
|
||||
}
|
||||
|
||||
private static boolean jmapHelp() {
|
||||
// --heap -> -heap
|
||||
// --binaryheap -> -heap:format=b
|
||||
// --histo -> -histo
|
||||
// --clstats -> -clstats
|
||||
// --finalizerinfo -> -finalizerinfo
|
||||
|
||||
System.out.println(" <no option>\tto print same info as Solaris pmap");
|
||||
System.out.println(" --heap\tto print java heap summary");
|
||||
System.out.println(" --binaryheap\tto dump java heap in hprof binary format");
|
||||
System.out.println(" --histo\tto print histogram of java object heap");
|
||||
System.out.println(" --clstats\tto print class loader statistics");
|
||||
System.out.println(" --finalizerinfo\tto print information on objects awaiting finalization");
|
||||
return commonHelp();
|
||||
}
|
||||
|
||||
private static boolean jstackHelp() {
|
||||
// --locks -> -l
|
||||
// --mixed -> -m
|
||||
System.out.println(" --locks\tto print java.util.concurrent locks");
|
||||
System.out.println(" --mixed\tto print both java and native frames (mixed mode)");
|
||||
return commonHelp();
|
||||
}
|
||||
|
||||
private static boolean toolHelp(String toolName) {
|
||||
if (toolName.equals("jstack")) {
|
||||
return jstackHelp();
|
||||
}
|
||||
if (toolName.equals("jinfo")) {
|
||||
return jinfoHelp();
|
||||
}
|
||||
if (toolName.equals("jmap")) {
|
||||
return jmapHelp();
|
||||
}
|
||||
if (toolName.equals("hsdb") || toolName.equals("clhsdb")) {
|
||||
return commonHelp();
|
||||
}
|
||||
return launcherHelp();
|
||||
}
|
||||
|
||||
private static void runCLHSDB(String[] oldArgs) {
|
||||
SAGetopt sg = new SAGetopt(oldArgs);
|
||||
String[] longOpts = {"exe=", "core=", "pid="};
|
||||
|
||||
ArrayList<String> newArgs = new ArrayList();
|
||||
String exeORpid = null;
|
||||
String core = null;
|
||||
String s = null;
|
||||
|
||||
while((s = sg.next(null, longOpts)) != null) {
|
||||
if (s.equals("exe")) {
|
||||
exeORpid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("core")) {
|
||||
core = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("pid")) {
|
||||
exeORpid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (exeORpid != null) {
|
||||
newArgs.add(exeORpid);
|
||||
if (core != null) {
|
||||
newArgs.add(core);
|
||||
}
|
||||
}
|
||||
CLHSDB.main(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
private static void runHSDB(String[] oldArgs) {
|
||||
SAGetopt sg = new SAGetopt(oldArgs);
|
||||
String[] longOpts = {"exe=", "core=", "pid="};
|
||||
|
||||
ArrayList<String> newArgs = new ArrayList();
|
||||
String exeORpid = null;
|
||||
String core = null;
|
||||
String s = null;
|
||||
|
||||
while((s = sg.next(null, longOpts)) != null) {
|
||||
if (s.equals("exe")) {
|
||||
exeORpid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("core")) {
|
||||
core = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("pid")) {
|
||||
exeORpid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (exeORpid != null) {
|
||||
newArgs.add(exeORpid);
|
||||
if (core != null) {
|
||||
newArgs.add(core);
|
||||
}
|
||||
}
|
||||
HSDB.main(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
private static void runJSTACK(String[] oldArgs) {
|
||||
SAGetopt sg = new SAGetopt(oldArgs);
|
||||
String[] longOpts = {"exe=", "core=", "pid=",
|
||||
"mixed", "locks"};
|
||||
|
||||
ArrayList<String> newArgs = new ArrayList();
|
||||
String exeORpid = null;
|
||||
String core = null;
|
||||
String s = null;
|
||||
|
||||
while((s = sg.next(null, longOpts)) != null) {
|
||||
if (s.equals("exe")) {
|
||||
exeORpid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("core")) {
|
||||
core = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("pid")) {
|
||||
exeORpid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("mixed")) {
|
||||
newArgs.add("-m");
|
||||
continue;
|
||||
}
|
||||
if (s.equals("locks")) {
|
||||
newArgs.add("-l");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (exeORpid != null) {
|
||||
newArgs.add(exeORpid);
|
||||
if (core != null) {
|
||||
newArgs.add(core);
|
||||
}
|
||||
}
|
||||
|
||||
JStack.main(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
private static void runJMAP(String[] oldArgs) {
|
||||
SAGetopt sg = new SAGetopt(oldArgs);
|
||||
String[] longOpts = {"exe=", "core=", "pid=",
|
||||
"heap", "binaryheap", "histo", "clstats", "finalizerinfo"};
|
||||
|
||||
ArrayList<String> newArgs = new ArrayList();
|
||||
String exeORpid = null;
|
||||
String core = null;
|
||||
String s = null;
|
||||
|
||||
while((s = sg.next(null, longOpts)) != null) {
|
||||
if (s.equals("exe")) {
|
||||
exeORpid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("core")) {
|
||||
core = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("pid")) {
|
||||
exeORpid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("heap")) {
|
||||
newArgs.add("-heap");
|
||||
continue;
|
||||
}
|
||||
if (s.equals("binaryheap")) {
|
||||
newArgs.add("-heap:format=b");
|
||||
continue;
|
||||
}
|
||||
if (s.equals("histo")) {
|
||||
newArgs.add("-histo");
|
||||
continue;
|
||||
}
|
||||
if (s.equals("clstats")) {
|
||||
newArgs.add("-clstats");
|
||||
continue;
|
||||
}
|
||||
if (s.equals("finalizerinfo")) {
|
||||
newArgs.add("-finalizerinfo");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (exeORpid != null) {
|
||||
newArgs.add(exeORpid);
|
||||
if (core != null) {
|
||||
newArgs.add(core);
|
||||
}
|
||||
}
|
||||
|
||||
JMap.main(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
private static void runJINFO(String[] oldArgs) {
|
||||
SAGetopt sg = new SAGetopt(oldArgs);
|
||||
String[] longOpts = {"exe=", "core=", "pid=",
|
||||
"flags", "sysprops"};
|
||||
|
||||
ArrayList<String> newArgs = new ArrayList();
|
||||
String exeORpid = null;
|
||||
String core = null;
|
||||
String s = null;
|
||||
|
||||
while((s = sg.next(null, longOpts)) != null) {
|
||||
if (s.equals("exe")) {
|
||||
exeORpid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("core")) {
|
||||
core = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("pid")) {
|
||||
exeORpid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("flags")) {
|
||||
newArgs.add("-flags");
|
||||
continue;
|
||||
}
|
||||
if (s.equals("sysprops")) {
|
||||
newArgs.add("-sysprops");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (exeORpid != null) {
|
||||
newArgs.add(exeORpid);
|
||||
if (core != null) {
|
||||
newArgs.add(core);
|
||||
}
|
||||
}
|
||||
|
||||
JInfo.main(newArgs.toArray(new String[newArgs.size()]));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Provide a help
|
||||
if (args.length == 0) {
|
||||
launcherHelp();
|
||||
return;
|
||||
}
|
||||
// No arguments imply help for jstack, jmap, jinfo but launch clhsdb and hsdb
|
||||
if (args.length == 1 && !args[0].equals("clhsdb") && !args[0].equals("hsdb")) {
|
||||
toolHelp(args[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (String arg : args) {
|
||||
if (arg.equals("-h") || arg.equals("-help") || arg.equals("--help")) {
|
||||
toolHelp(args[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String[] oldArgs = Arrays.copyOfRange(args, 1, args.length);
|
||||
|
||||
// Run SA interactive mode
|
||||
if (args[0].equals("clhsdb")) {
|
||||
runCLHSDB(oldArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args[0].equals("hsdb")) {
|
||||
runHSDB(oldArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
// Run SA tmtools mode
|
||||
if (args[0].equals("jstack")) {
|
||||
runJSTACK(oldArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args[0].equals("jmap")) {
|
||||
runJMAP(oldArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args[0].equals("jinfo")) {
|
||||
runJINFO(oldArgs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
@ -37,6 +37,21 @@ import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
public abstract class AARCH64ThreadContext implements ThreadContext {
|
||||
// Taken from /usr/include/asm/sigcontext.h on Linux/AARCH64.
|
||||
|
||||
// /*
|
||||
// * Signal context structure - contains all info to do with the state
|
||||
// * before the signal handler was invoked.
|
||||
// */
|
||||
// struct sigcontext {
|
||||
// __u64 fault_address;
|
||||
// /* AArch64 registers */
|
||||
// __u64 regs[31];
|
||||
// __u64 sp;
|
||||
// __u64 pc;
|
||||
// __u64 pstate;
|
||||
// /* 4K reserved for FP/SIMD state and future expansion */
|
||||
// __u8 __reserved[4096] __attribute__((__aligned__(16)));
|
||||
// };
|
||||
|
||||
// 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
|
||||
@ -78,8 +93,9 @@ public abstract class AARCH64ThreadContext implements ThreadContext {
|
||||
public static final int LR = 30;
|
||||
public static final int SP = 31;
|
||||
public static final int PC = 32;
|
||||
public static final int PSTATE = 33;
|
||||
|
||||
public static final int NPRGREG = 33;
|
||||
public static final int NPRGREG = 34;
|
||||
|
||||
private long[] data;
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
package sun.jvm.hotspot.gc.g1;
|
||||
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
|
||||
import sun.jvm.hotspot.debugger.Address;
|
||||
import sun.jvm.hotspot.runtime.VM;
|
||||
import sun.jvm.hotspot.runtime.VMObject;
|
||||
import sun.jvm.hotspot.types.CIntegerField;
|
||||
import sun.jvm.hotspot.types.Type;
|
||||
import sun.jvm.hotspot.types.TypeDataBase;
|
||||
|
||||
public class G1Allocator extends VMObject {
|
||||
|
||||
//size_t _summary_bytes_used;
|
||||
static private CIntegerField summaryBytesUsedField;
|
||||
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
public void update(Observable o, Object data) {
|
||||
initialize(VM.getVM().getTypeDataBase());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static private synchronized void initialize(TypeDataBase db) {
|
||||
Type type = db.lookupType("G1Allocator");
|
||||
|
||||
summaryBytesUsedField = type.getCIntegerField("_summary_bytes_used");
|
||||
}
|
||||
|
||||
public long getSummaryBytes() {
|
||||
return summaryBytesUsedField.getValue(addr);
|
||||
}
|
||||
|
||||
public G1Allocator(Address addr) {
|
||||
super(addr);
|
||||
|
||||
}
|
||||
}
|
@ -36,6 +36,7 @@ import sun.jvm.hotspot.memory.MemRegion;
|
||||
import sun.jvm.hotspot.runtime.VM;
|
||||
import sun.jvm.hotspot.runtime.VMObjectFactory;
|
||||
import sun.jvm.hotspot.types.AddressField;
|
||||
import sun.jvm.hotspot.types.CIntegerField;
|
||||
import sun.jvm.hotspot.types.Type;
|
||||
import sun.jvm.hotspot.types.TypeDataBase;
|
||||
|
||||
@ -46,8 +47,8 @@ public class G1CollectedHeap extends CollectedHeap {
|
||||
static private long hrmFieldOffset;
|
||||
// MemRegion _g1_reserved;
|
||||
static private long g1ReservedFieldOffset;
|
||||
// G1Allocator* _allocator
|
||||
static private AddressField g1Allocator;
|
||||
// size_t _summary_bytes_used;
|
||||
static private CIntegerField summaryBytesUsedField;
|
||||
// G1MonitoringSupport* _g1mm;
|
||||
static private AddressField g1mmField;
|
||||
// HeapRegionSet _old_set;
|
||||
@ -67,7 +68,7 @@ public class G1CollectedHeap extends CollectedHeap {
|
||||
Type type = db.lookupType("G1CollectedHeap");
|
||||
|
||||
hrmFieldOffset = type.getField("_hrm").getOffset();
|
||||
g1Allocator = type.getAddressField("_allocator");
|
||||
summaryBytesUsedField = type.getCIntegerField("_summary_bytes_used");
|
||||
g1mmField = type.getAddressField("_g1mm");
|
||||
oldSetFieldOffset = type.getField("_old_set").getOffset();
|
||||
humongousSetFieldOffset = type.getField("_humongous_set").getOffset();
|
||||
@ -78,7 +79,7 @@ public class G1CollectedHeap extends CollectedHeap {
|
||||
}
|
||||
|
||||
public long used() {
|
||||
return allocator().getSummaryBytes();
|
||||
return summaryBytesUsedField.getValue(addr);
|
||||
}
|
||||
|
||||
public long n_regions() {
|
||||
@ -96,11 +97,6 @@ public class G1CollectedHeap extends CollectedHeap {
|
||||
return (G1MonitoringSupport) VMObjectFactory.newObject(G1MonitoringSupport.class, g1mmAddr);
|
||||
}
|
||||
|
||||
public G1Allocator allocator() {
|
||||
Address g1AllocatorAddr = g1Allocator.getValue(addr);
|
||||
return (G1Allocator) VMObjectFactory.newObject(G1Allocator.class, g1AllocatorAddr);
|
||||
}
|
||||
|
||||
public HeapRegionSetBase oldSet() {
|
||||
Address oldSetAddr = addr.addOffsetTo(oldSetFieldOffset);
|
||||
return (HeapRegionSetBase) VMObjectFactory.newObject(HeapRegionSetBase.class,
|
||||
|
@ -1550,6 +1550,13 @@ void os::print_dll_info(outputStream *st) {
|
||||
LoadedLibraries::print(st);
|
||||
}
|
||||
|
||||
void os::get_summary_os_info(char* buf, size_t buflen) {
|
||||
// There might be something more readable than uname results for AIX.
|
||||
struct utsname name;
|
||||
uname(&name);
|
||||
snprintf(buf, buflen, "%s %s", name.release, name.version);
|
||||
}
|
||||
|
||||
void os::print_os_info(outputStream* st) {
|
||||
st->print("OS:");
|
||||
|
||||
@ -1654,6 +1661,17 @@ void os::print_memory_info(outputStream* st) {
|
||||
}
|
||||
}
|
||||
|
||||
// Get a string for the cpuinfo that is a summary of the cpu type
|
||||
void os::get_summary_cpu_info(char* buf, size_t buflen) {
|
||||
// This looks good
|
||||
os::Aix::cpuinfo_t ci;
|
||||
if (os::Aix::get_cpuinfo(&ci)) {
|
||||
strncpy(buf, ci.version, buflen);
|
||||
} else {
|
||||
strncpy(buf, "AIX", buflen);
|
||||
}
|
||||
}
|
||||
|
||||
void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
|
||||
}
|
||||
|
||||
|
@ -1600,24 +1600,6 @@ void* os::dll_lookup(void* handle, const char* name) {
|
||||
return dlsym(handle, name);
|
||||
}
|
||||
|
||||
|
||||
static bool _print_ascii_file(const char* filename, outputStream* st) {
|
||||
int fd = ::open(filename, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buf[32];
|
||||
int bytes;
|
||||
while ((bytes = ::read(fd, buf, sizeof(buf))) > 0) {
|
||||
st->print_raw(buf, bytes);
|
||||
}
|
||||
|
||||
::close(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) {
|
||||
outputStream * out = (outputStream *) param;
|
||||
out->print_cr(PTR_FORMAT " \t%s", base_address, name);
|
||||
@ -1678,15 +1660,38 @@ int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *pa
|
||||
#endif
|
||||
}
|
||||
|
||||
void os::print_os_info_brief(outputStream* st) {
|
||||
st->print("Bsd");
|
||||
void os::get_summary_os_info(char* buf, size_t buflen) {
|
||||
// These buffers are small because we want this to be brief
|
||||
// and not use a lot of stack while generating the hs_err file.
|
||||
char os[100];
|
||||
size_t size = sizeof(os);
|
||||
int mib_kern[] = { CTL_KERN, KERN_OSTYPE };
|
||||
if (sysctl(mib_kern, 2, os, &size, NULL, 0) < 0) {
|
||||
#ifdef __APPLE__
|
||||
strncpy(os, "Darwin", sizeof(os));
|
||||
#elif __OpenBSD__
|
||||
strncpy(os, "OpenBSD", sizeof(os));
|
||||
#else
|
||||
strncpy(os, "BSD", sizeof(os));
|
||||
#endif
|
||||
}
|
||||
|
||||
char release[100];
|
||||
size = sizeof(release);
|
||||
int mib_release[] = { CTL_KERN, KERN_OSRELEASE };
|
||||
if (sysctl(mib_release, 2, release, &size, NULL, 0) < 0) {
|
||||
// if error, leave blank
|
||||
strncpy(release, "", sizeof(release));
|
||||
}
|
||||
snprintf(buf, buflen, "%s %s", os, release);
|
||||
}
|
||||
|
||||
void os::print_os_info_brief(outputStream* st) {
|
||||
os::Posix::print_uname_info(st);
|
||||
}
|
||||
|
||||
void os::print_os_info(outputStream* st) {
|
||||
st->print("OS:");
|
||||
st->print("Bsd");
|
||||
|
||||
os::Posix::print_uname_info(st);
|
||||
|
||||
@ -1699,6 +1704,33 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
|
||||
// Nothing to do for now.
|
||||
}
|
||||
|
||||
void os::get_summary_cpu_info(char* buf, size_t buflen) {
|
||||
unsigned int mhz;
|
||||
size_t size = sizeof(mhz);
|
||||
int mib[] = { CTL_HW, HW_CPU_FREQ };
|
||||
if (sysctl(mib, 2, &mhz, &size, NULL, 0) < 0) {
|
||||
mhz = 1; // looks like an error but can be divided by
|
||||
} else {
|
||||
mhz /= 1000000; // reported in millions
|
||||
}
|
||||
|
||||
char model[100];
|
||||
size = sizeof(model);
|
||||
int mib_model[] = { CTL_HW, HW_MODEL };
|
||||
if (sysctl(mib_model, 2, model, &size, NULL, 0) < 0) {
|
||||
strncpy(model, cpu_arch, sizeof(model));
|
||||
}
|
||||
|
||||
char machine[100];
|
||||
size = sizeof(machine);
|
||||
int mib_machine[] = { CTL_HW, HW_MACHINE };
|
||||
if (sysctl(mib_machine, 2, machine, &size, NULL, 0) < 0) {
|
||||
strncpy(machine, "", sizeof(machine));
|
||||
}
|
||||
|
||||
snprintf(buf, buflen, "%s %s %d MHz", model, machine, mhz);
|
||||
}
|
||||
|
||||
void os::print_memory_info(outputStream* st) {
|
||||
|
||||
st->print("Memory:");
|
||||
@ -1709,11 +1741,6 @@ void os::print_memory_info(outputStream* st) {
|
||||
st->print("(" UINT64_FORMAT "k free)",
|
||||
os::available_memory() >> 10);
|
||||
st->cr();
|
||||
|
||||
// meminfo
|
||||
st->print("\n/proc/meminfo:\n");
|
||||
_print_ascii_file("/proc/meminfo", st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void os::print_siginfo(outputStream* st, void* siginfo) {
|
||||
|
@ -2043,31 +2043,96 @@ void os::print_os_info(outputStream* st) {
|
||||
// Searching for the debian_version file is the last resort. It contains
|
||||
// an informative string like "6.0.6" or "wheezy/sid". Because of this
|
||||
// "Debian " is printed before the contents of the debian_version file.
|
||||
void os::Linux::print_distro_info(outputStream* st) {
|
||||
if (!_print_ascii_file("/etc/oracle-release", st) &&
|
||||
!_print_ascii_file("/etc/mandriva-release", st) &&
|
||||
!_print_ascii_file("/etc/mandrake-release", st) &&
|
||||
!_print_ascii_file("/etc/sun-release", st) &&
|
||||
!_print_ascii_file("/etc/redhat-release", st) &&
|
||||
!_print_ascii_file("/etc/lsb-release", st) &&
|
||||
!_print_ascii_file("/etc/SuSE-release", st) &&
|
||||
!_print_ascii_file("/etc/turbolinux-release", st) &&
|
||||
!_print_ascii_file("/etc/gentoo-release", st) &&
|
||||
!_print_ascii_file("/etc/ltib-release", st) &&
|
||||
!_print_ascii_file("/etc/angstrom-version", st) &&
|
||||
!_print_ascii_file("/etc/system-release", st) &&
|
||||
!_print_ascii_file("/etc/os-release", st)) {
|
||||
|
||||
if (file_exists("/etc/debian_version")) {
|
||||
st->print("Debian ");
|
||||
_print_ascii_file("/etc/debian_version", st);
|
||||
} else {
|
||||
st->print("Linux");
|
||||
const char* distro_files[] = {
|
||||
"/etc/oracle-release",
|
||||
"/etc/mandriva-release",
|
||||
"/etc/mandrake-release",
|
||||
"/etc/sun-release",
|
||||
"/etc/redhat-release",
|
||||
"/etc/lsb-release",
|
||||
"/etc/SuSE-release",
|
||||
"/etc/turbolinux-release",
|
||||
"/etc/gentoo-release",
|
||||
"/etc/ltib-release",
|
||||
"/etc/angstrom-version",
|
||||
"/etc/system-release",
|
||||
"/etc/os-release",
|
||||
NULL };
|
||||
|
||||
void os::Linux::print_distro_info(outputStream* st) {
|
||||
for (int i = 0;; i++) {
|
||||
const char* file = distro_files[i];
|
||||
if (file == NULL) {
|
||||
break; // done
|
||||
}
|
||||
// If file prints, we found it.
|
||||
if (_print_ascii_file(file, st)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_exists("/etc/debian_version")) {
|
||||
st->print("Debian ");
|
||||
_print_ascii_file("/etc/debian_version", st);
|
||||
} else {
|
||||
st->print("Linux");
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
|
||||
static void parse_os_info(char* distro, size_t length, const char* file) {
|
||||
FILE* fp = fopen(file, "r");
|
||||
if (fp != NULL) {
|
||||
char buf[256];
|
||||
// get last line of the file.
|
||||
while (fgets(buf, sizeof(buf), fp)) { }
|
||||
// Edit out extra stuff in expected ubuntu format
|
||||
if (strstr(buf, "DISTRIB_DESCRIPTION=") != NULL) {
|
||||
char* ptr = strstr(buf, "\""); // the name is in quotes
|
||||
if (ptr != NULL) {
|
||||
ptr++; // go beyond first quote
|
||||
char* nl = strchr(ptr, '\"');
|
||||
if (nl != NULL) *nl = '\0';
|
||||
strncpy(distro, ptr, length);
|
||||
} else {
|
||||
ptr = strstr(buf, "=");
|
||||
ptr++; // go beyond equals then
|
||||
char* nl = strchr(ptr, '\n');
|
||||
if (nl != NULL) *nl = '\0';
|
||||
strncpy(distro, ptr, length);
|
||||
}
|
||||
} else {
|
||||
// if not in expected Ubuntu format, print out whole line minus \n
|
||||
char* nl = strchr(buf, '\n');
|
||||
if (nl != NULL) *nl = '\0';
|
||||
strncpy(distro, buf, length);
|
||||
}
|
||||
// close distro file
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
void os::get_summary_os_info(char* buf, size_t buflen) {
|
||||
for (int i = 0;; i++) {
|
||||
const char* file = distro_files[i];
|
||||
if (file == NULL) {
|
||||
break; // ran out of distro_files
|
||||
}
|
||||
if (file_exists(file)) {
|
||||
parse_os_info(buf, buflen, file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// special case for debian
|
||||
if (file_exists("/etc/debian_version")) {
|
||||
strncpy(buf, "Debian ", buflen);
|
||||
parse_os_info(&buf[7], buflen-7, "/etc/debian_version");
|
||||
} else {
|
||||
strncpy(buf, "Linux", buflen);
|
||||
}
|
||||
}
|
||||
|
||||
void os::Linux::print_libversion_info(outputStream* st) {
|
||||
// libc, pthread
|
||||
st->print("libc:");
|
||||
@ -2150,6 +2215,48 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
|
||||
}
|
||||
}
|
||||
|
||||
const char* search_string = IA32_ONLY("model name") AMD64_ONLY("model name")
|
||||
IA64_ONLY("") SPARC_ONLY("cpu")
|
||||
ARM32_ONLY("Processor") PPC_ONLY("Processor") AARCH64_ONLY("Processor");
|
||||
|
||||
// Parses the cpuinfo file for string representing the model name.
|
||||
void os::get_summary_cpu_info(char* cpuinfo, size_t length) {
|
||||
FILE* fp = fopen("/proc/cpuinfo", "r");
|
||||
if (fp != NULL) {
|
||||
while (!feof(fp)) {
|
||||
char buf[256];
|
||||
if (fgets(buf, sizeof(buf), fp)) {
|
||||
char* start = strstr(buf, search_string);
|
||||
if (start != NULL) {
|
||||
char *ptr = start + strlen(search_string);
|
||||
char *end = buf + strlen(buf);
|
||||
while (ptr != end) {
|
||||
// skip whitespace and colon for the rest of the name.
|
||||
if (*ptr != ' ' && *ptr != '\t' && *ptr != ':') {
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
if (ptr != end) {
|
||||
// reasonable string, get rid of newline and keep the rest
|
||||
char* nl = strchr(buf, '\n');
|
||||
if (nl != NULL) *nl = '\0';
|
||||
strncpy(cpuinfo, ptr, length);
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
// cpuinfo not found or parsing failed, just print generic string. The entire
|
||||
// /proc/cpuinfo file will be printed later in the file (or enough of it for x86)
|
||||
strncpy(cpuinfo, IA32_ONLY("x86_32") AMD64_ONLY("x86_32")
|
||||
IA64_ONLY("IA64") SPARC_ONLY("sparcv9")
|
||||
ARM32_ONLY("ARM") PPC_ONLY("PPC64") AARCH64_ONLY("AArch64"), length);
|
||||
}
|
||||
|
||||
void os::print_siginfo(outputStream* st, void* siginfo) {
|
||||
const siginfo_t* si = (const siginfo_t*)siginfo;
|
||||
|
||||
|
@ -236,6 +236,15 @@ void os::Posix::print_uname_info(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool os::get_host_name(char* buf, size_t buflen) {
|
||||
struct utsname name;
|
||||
uname(&name);
|
||||
jio_snprintf(buf, buflen, "%s", name.nodename);
|
||||
return true;
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
bool os::has_allocatable_memory_limit(julong* limit) {
|
||||
struct rlimit rlim;
|
||||
int getrlimit_res = getrlimit(RLIMIT_AS, &rlim);
|
||||
|
@ -1971,6 +1971,26 @@ void os::Solaris::print_distro_info(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void os::get_summary_os_info(char* buf, size_t buflen) {
|
||||
strncpy(buf, "Solaris", buflen); // default to plain solaris
|
||||
FILE* fp = fopen("/etc/release", "r");
|
||||
if (fp != NULL) {
|
||||
char tmp[256];
|
||||
// Only get the first line and chop out everything but the os name.
|
||||
if (fgets(tmp, sizeof(tmp), fp)) {
|
||||
char* ptr = tmp;
|
||||
// skip past whitespace characters
|
||||
while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')) ptr++;
|
||||
if (*ptr != '\0') {
|
||||
char* nl = strchr(ptr, '\n');
|
||||
if (nl != NULL) *nl = '\0';
|
||||
strncpy(buf, ptr, buflen);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
void os::Solaris::print_libversion_info(outputStream* st) {
|
||||
st->print(" (T2 libthread)");
|
||||
st->cr();
|
||||
@ -1998,6 +2018,22 @@ static bool check_addr0(outputStream* st) {
|
||||
return status;
|
||||
}
|
||||
|
||||
void os::get_summary_cpu_info(char* buf, size_t buflen) {
|
||||
// Get MHz with system call. We don't seem to already have this.
|
||||
processor_info_t stats;
|
||||
processorid_t id = getcpuid();
|
||||
int clock = 0;
|
||||
if (processor_info(id, &stats) != -1) {
|
||||
clock = stats.pi_clock; // pi_processor_type isn't more informative than below
|
||||
}
|
||||
#ifdef AMD64
|
||||
snprintf(buf, buflen, "x86 64 bit %d MHz", clock);
|
||||
#else
|
||||
// must be sparc
|
||||
snprintf(buf, buflen, "Sparcv9 64 bit %d MHz", clock);
|
||||
#endif
|
||||
}
|
||||
|
||||
void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
|
||||
// Nothing to do for now.
|
||||
}
|
||||
|
@ -1593,6 +1593,21 @@ int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *pa
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool os::get_host_name(char* buf, size_t buflen) {
|
||||
DWORD size = (DWORD)buflen;
|
||||
return (GetComputerNameEx(ComputerNameDnsHostname, buf, &size) == TRUE);
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
void os::get_summary_os_info(char* buf, size_t buflen) {
|
||||
stringStream sst(buf, buflen);
|
||||
os::win32::print_windows_version(&sst);
|
||||
// chop off newline character
|
||||
char* nl = strchr(buf, '\n');
|
||||
if (nl != NULL) *nl = '\0';
|
||||
}
|
||||
|
||||
void os::print_os_info_brief(outputStream* st) {
|
||||
os::print_os_info(st);
|
||||
}
|
||||
@ -1600,15 +1615,14 @@ void os::print_os_info_brief(outputStream* st) {
|
||||
void os::print_os_info(outputStream* st) {
|
||||
#ifdef ASSERT
|
||||
char buffer[1024];
|
||||
DWORD size = sizeof(buffer);
|
||||
st->print(" HostName: ");
|
||||
if (GetComputerNameEx(ComputerNameDnsHostname, buffer, &size)) {
|
||||
st->print("%s", buffer);
|
||||
st->print("HostName: ");
|
||||
if (get_host_name(buffer, sizeof(buffer))) {
|
||||
st->print("%s ", buffer);
|
||||
} else {
|
||||
st->print("N/A");
|
||||
st->print("N/A ");
|
||||
}
|
||||
#endif
|
||||
st->print(" OS:");
|
||||
st->print("OS:");
|
||||
os::win32::print_windows_version(st);
|
||||
}
|
||||
|
||||
@ -1738,6 +1752,23 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
|
||||
// Nothing to do for now.
|
||||
}
|
||||
|
||||
void os::get_summary_cpu_info(char* buf, size_t buflen) {
|
||||
HKEY key;
|
||||
DWORD status = RegOpenKey(HKEY_LOCAL_MACHINE,
|
||||
"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &key);
|
||||
if (status == ERROR_SUCCESS) {
|
||||
DWORD size = (DWORD)buflen;
|
||||
status = RegQueryValueEx(key, "ProcessorNameString", NULL, NULL, (byte*)buf, &size);
|
||||
if (status != ERROR_SUCCESS) {
|
||||
strncpy(buf, "## __CPU__", buflen);
|
||||
}
|
||||
RegCloseKey(key);
|
||||
} else {
|
||||
// Put generic cpu info to return
|
||||
strncpy(buf, "## __CPU__", buflen);
|
||||
}
|
||||
}
|
||||
|
||||
void os::print_memory_info(outputStream* st) {
|
||||
st->print("Memory:");
|
||||
st->print(" %dk page", os::vm_page_size()>>10);
|
||||
|
@ -809,6 +809,22 @@ Symbol* java_lang_Class::as_signature(oop java_class, bool intern_if_not_found,
|
||||
return name;
|
||||
}
|
||||
|
||||
// Returns the Java name for this Java mirror (Resource allocated)
|
||||
// See Klass::external_name().
|
||||
// For primitive type Java mirrors, its type name is returned.
|
||||
const char* java_lang_Class::as_external_name(oop java_class) {
|
||||
assert(java_lang_Class::is_instance(java_class), "must be a Class object");
|
||||
const char* name = NULL;
|
||||
if (is_primitive(java_class)) {
|
||||
name = type2name(primitive_type(java_class));
|
||||
} else {
|
||||
name = as_Klass(java_class)->external_name();
|
||||
}
|
||||
if (name == NULL) {
|
||||
name = "<null>";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
Klass* java_lang_Class::array_klass(oop java_class) {
|
||||
Klass* k = ((Klass*)java_class->metadata_field(_array_klass_offset));
|
||||
|
@ -276,6 +276,7 @@ class java_lang_Class : AllStatic {
|
||||
}
|
||||
static Symbol* as_signature(oop java_class, bool intern_if_not_found, TRAPS);
|
||||
static void print_signature(oop java_class, outputStream *st);
|
||||
static const char* as_external_name(oop java_class);
|
||||
// Testing
|
||||
static bool is_instance(oop obj);
|
||||
|
||||
|
@ -86,7 +86,7 @@ bool VerificationType::is_reference_assignable_from(
|
||||
VerificationType comp_this = get_component(context, CHECK_false);
|
||||
VerificationType comp_from = from.get_component(context, CHECK_false);
|
||||
if (!comp_this.is_bogus() && !comp_from.is_bogus()) {
|
||||
return comp_this.is_assignable_from(comp_from, context,
|
||||
return comp_this.is_component_assignable_from(comp_from, context,
|
||||
from_field_is_protected, CHECK_false);
|
||||
}
|
||||
}
|
||||
|
@ -297,6 +297,26 @@ class VerificationType VALUE_OBJ_CLASS_SPEC {
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if one array component type is assignable to another.
|
||||
// Same as is_assignable_from() except int primitives must be identical.
|
||||
bool is_component_assignable_from(
|
||||
const VerificationType& from, ClassVerifier* context,
|
||||
bool from_field_is_protected, TRAPS) const {
|
||||
if (equals(from) || is_bogus()) {
|
||||
return true;
|
||||
} else {
|
||||
switch(_u._data) {
|
||||
case Boolean:
|
||||
case Byte:
|
||||
case Char:
|
||||
case Short:
|
||||
return false;
|
||||
default:
|
||||
return is_assignable_from(from, context, from_field_is_protected, CHECK_false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VerificationType get_component(ClassVerifier* context, TRAPS) const;
|
||||
|
||||
int dimensions() const {
|
||||
|
@ -36,10 +36,11 @@
|
||||
#include "runtime/orderAccess.inline.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
|
||||
void CardTableModRefBS::non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
|
||||
OopsInGenClosure* cl,
|
||||
CardTableRS* ct,
|
||||
uint n_threads) {
|
||||
void CardTableModRefBSForCTRS::
|
||||
non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
|
||||
OopsInGenClosure* cl,
|
||||
CardTableRS* ct,
|
||||
uint n_threads) {
|
||||
assert(n_threads > 0, "expected n_threads > 0");
|
||||
assert(n_threads <= ParallelGCThreads,
|
||||
err_msg("n_threads: %u > ParallelGCThreads: %u", n_threads, ParallelGCThreads));
|
||||
@ -81,7 +82,7 @@ void CardTableModRefBS::non_clean_card_iterate_parallel_work(Space* sp, MemRegio
|
||||
}
|
||||
|
||||
void
|
||||
CardTableModRefBS::
|
||||
CardTableModRefBSForCTRS::
|
||||
process_stride(Space* sp,
|
||||
MemRegion used,
|
||||
jint stride, int n_strides,
|
||||
@ -170,7 +171,7 @@ process_stride(Space* sp,
|
||||
#endif
|
||||
|
||||
void
|
||||
CardTableModRefBS::
|
||||
CardTableModRefBSForCTRS::
|
||||
process_chunk_boundaries(Space* sp,
|
||||
DirtyCardToOopClosure* dcto_cl,
|
||||
MemRegion chunk_mr,
|
||||
@ -426,7 +427,7 @@ process_chunk_boundaries(Space* sp,
|
||||
#undef NOISY
|
||||
|
||||
void
|
||||
CardTableModRefBS::
|
||||
CardTableModRefBSForCTRS::
|
||||
get_LNC_array_for_space(Space* sp,
|
||||
jbyte**& lowest_non_clean,
|
||||
uintptr_t& lowest_non_clean_base_chunk_index,
|
||||
|
@ -39,13 +39,8 @@ class G1Allocator : public CHeapObj<mtGC> {
|
||||
protected:
|
||||
G1CollectedHeap* _g1h;
|
||||
|
||||
// Outside of GC pauses, the number of bytes used in all regions other
|
||||
// than the current allocation region.
|
||||
size_t _summary_bytes_used;
|
||||
|
||||
public:
|
||||
G1Allocator(G1CollectedHeap* heap) :
|
||||
_g1h(heap), _summary_bytes_used(0) { }
|
||||
G1Allocator(G1CollectedHeap* heap) : _g1h(heap) { }
|
||||
|
||||
static G1Allocator* create_allocator(G1CollectedHeap* g1h);
|
||||
|
||||
@ -59,32 +54,13 @@ public:
|
||||
virtual MutatorAllocRegion* mutator_alloc_region(AllocationContext_t context) = 0;
|
||||
virtual SurvivorGCAllocRegion* survivor_gc_alloc_region(AllocationContext_t context) = 0;
|
||||
virtual OldGCAllocRegion* old_gc_alloc_region(AllocationContext_t context) = 0;
|
||||
virtual size_t used() = 0;
|
||||
virtual size_t used_in_alloc_regions() = 0;
|
||||
virtual bool is_retained_old_region(HeapRegion* hr) = 0;
|
||||
|
||||
void reuse_retained_old_region(EvacuationInfo& evacuation_info,
|
||||
OldGCAllocRegion* old,
|
||||
HeapRegion** retained);
|
||||
|
||||
size_t used_unlocked() const {
|
||||
return _summary_bytes_used;
|
||||
}
|
||||
|
||||
void increase_used(size_t bytes) {
|
||||
_summary_bytes_used += bytes;
|
||||
}
|
||||
|
||||
void decrease_used(size_t bytes) {
|
||||
assert(_summary_bytes_used >= bytes,
|
||||
err_msg("invariant: _summary_bytes_used: " SIZE_FORMAT " should be >= bytes: " SIZE_FORMAT,
|
||||
_summary_bytes_used, bytes));
|
||||
_summary_bytes_used -= bytes;
|
||||
}
|
||||
|
||||
void set_used(size_t bytes) {
|
||||
_summary_bytes_used = bytes;
|
||||
}
|
||||
|
||||
virtual HeapRegion* new_heap_region(uint hrs_index,
|
||||
G1BlockOffsetSharedArray* sharedOffsetArray,
|
||||
MemRegion mr) {
|
||||
@ -133,10 +109,10 @@ public:
|
||||
return &_old_gc_alloc_region;
|
||||
}
|
||||
|
||||
virtual size_t used() {
|
||||
virtual size_t used_in_alloc_regions() {
|
||||
assert(Heap_lock->owner() != NULL,
|
||||
"Should be owned on this thread's behalf.");
|
||||
size_t result = _summary_bytes_used;
|
||||
size_t result = 0;
|
||||
|
||||
// Read only once in case it is set to NULL concurrently
|
||||
HeapRegion* hr = mutator_alloc_region(AllocationContext::current())->get();
|
||||
|
@ -632,7 +632,7 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(uint first,
|
||||
check_bitmaps("Humongous Region Allocation", first_hr);
|
||||
|
||||
assert(first_hr->used() == word_size * HeapWordSize, "invariant");
|
||||
_allocator->increase_used(first_hr->used());
|
||||
increase_used(first_hr->used());
|
||||
_humongous_set.add(first_hr);
|
||||
|
||||
return new_obj;
|
||||
@ -998,7 +998,7 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) {
|
||||
if ((prev_last_region != NULL) && (start_region == prev_last_region)) {
|
||||
start_address = start_region->end();
|
||||
if (start_address > last_address) {
|
||||
_allocator->increase_used(word_size * HeapWordSize);
|
||||
increase_used(word_size * HeapWordSize);
|
||||
start_region->set_top(last_address + 1);
|
||||
continue;
|
||||
}
|
||||
@ -1012,7 +1012,7 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, size_t count) {
|
||||
if (!_hrm.allocate_containing_regions(curr_range, &commits)) {
|
||||
return false;
|
||||
}
|
||||
_allocator->increase_used(word_size * HeapWordSize);
|
||||
increase_used(word_size * HeapWordSize);
|
||||
if (commits != 0) {
|
||||
ergo_verbose1(ErgoHeapSizing,
|
||||
"attempt heap expansion",
|
||||
@ -1104,7 +1104,7 @@ void G1CollectedHeap::fill_archive_regions(MemRegion* ranges, size_t count) {
|
||||
if (start_address != bottom_address) {
|
||||
size_t fill_size = pointer_delta(start_address, bottom_address);
|
||||
G1CollectedHeap::fill_with_objects(bottom_address, fill_size);
|
||||
_allocator->increase_used(fill_size * HeapWordSize);
|
||||
increase_used(fill_size * HeapWordSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1917,7 +1917,6 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
|
||||
_ref_processor_cm(NULL),
|
||||
_ref_processor_stw(NULL),
|
||||
_bot_shared(NULL),
|
||||
_evac_failure_scan_stack(NULL),
|
||||
_cg1r(NULL),
|
||||
_g1mm(NULL),
|
||||
_refine_cte_cl(NULL),
|
||||
@ -1930,6 +1929,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
|
||||
_free_regions_coming(false),
|
||||
_young_list(new YoungList(this)),
|
||||
_gc_time_stamp(0),
|
||||
_summary_bytes_used(0),
|
||||
_survivor_plab_stats(YoungPLABSize, PLABWeight),
|
||||
_old_plab_stats(OldPLABSize, PLABWeight),
|
||||
_expand_heap_after_alloc_failure(true),
|
||||
@ -2204,6 +2204,11 @@ jint G1CollectedHeap::initialize() {
|
||||
|
||||
G1StringDedup::initialize();
|
||||
|
||||
_preserved_objs = NEW_C_HEAP_ARRAY(OopAndMarkOopStack, ParallelGCThreads, mtGC);
|
||||
for (uint i = 0; i < ParallelGCThreads; i++) {
|
||||
new (&_preserved_objs[i]) OopAndMarkOopStack();
|
||||
}
|
||||
|
||||
return JNI_OK;
|
||||
}
|
||||
|
||||
@ -2371,7 +2376,7 @@ void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl,
|
||||
|
||||
// Computes the sum of the storage used by the various regions.
|
||||
size_t G1CollectedHeap::used() const {
|
||||
size_t result = _allocator->used();
|
||||
size_t result = _summary_bytes_used + _allocator->used_in_alloc_regions();
|
||||
if (_archive_allocator != NULL) {
|
||||
result += _archive_allocator->used();
|
||||
}
|
||||
@ -2379,7 +2384,7 @@ size_t G1CollectedHeap::used() const {
|
||||
}
|
||||
|
||||
size_t G1CollectedHeap::used_unlocked() const {
|
||||
return _allocator->used_unlocked();
|
||||
return _summary_bytes_used;
|
||||
}
|
||||
|
||||
class SumUsedClosure: public HeapRegionClosure {
|
||||
@ -4102,7 +4107,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||
_young_list->reset_auxilary_lists();
|
||||
|
||||
if (evacuation_failed()) {
|
||||
_allocator->set_used(recalculate_used());
|
||||
set_used(recalculate_used());
|
||||
if (_archive_allocator != NULL) {
|
||||
_archive_allocator->clear_used();
|
||||
}
|
||||
@ -4114,7 +4119,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||
} else {
|
||||
// The "used" of the the collection set have already been subtracted
|
||||
// when they were freed. Add in the bytes evacuated.
|
||||
_allocator->increase_used(g1_policy()->bytes_copied_during_gc());
|
||||
increase_used(g1_policy()->bytes_copied_during_gc());
|
||||
}
|
||||
|
||||
if (collector_state()->during_initial_mark_pause()) {
|
||||
@ -4255,21 +4260,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void G1CollectedHeap::init_for_evac_failure(OopsInHeapRegionClosure* cl) {
|
||||
_drain_in_progress = false;
|
||||
set_evac_failure_closure(cl);
|
||||
_evac_failure_scan_stack = new (ResourceObj::C_HEAP, mtGC) GrowableArray<oop>(40, true);
|
||||
}
|
||||
|
||||
void G1CollectedHeap::finalize_for_evac_failure() {
|
||||
assert(_evac_failure_scan_stack != NULL &&
|
||||
_evac_failure_scan_stack->length() == 0,
|
||||
"Postcondition");
|
||||
assert(!_drain_in_progress, "Postcondition");
|
||||
delete _evac_failure_scan_stack;
|
||||
_evac_failure_scan_stack = NULL;
|
||||
}
|
||||
|
||||
void G1CollectedHeap::remove_self_forwarding_pointers() {
|
||||
double remove_self_forwards_start = os::elapsedTime();
|
||||
|
||||
@ -4277,104 +4267,30 @@ void G1CollectedHeap::remove_self_forwarding_pointers() {
|
||||
workers()->run_task(&rsfp_task);
|
||||
|
||||
// Now restore saved marks, if any.
|
||||
assert(_objs_with_preserved_marks.size() ==
|
||||
_preserved_marks_of_objs.size(), "Both or none.");
|
||||
while (!_objs_with_preserved_marks.is_empty()) {
|
||||
oop obj = _objs_with_preserved_marks.pop();
|
||||
markOop m = _preserved_marks_of_objs.pop();
|
||||
obj->set_mark(m);
|
||||
for (uint i = 0; i < ParallelGCThreads; i++) {
|
||||
OopAndMarkOopStack& cur = _preserved_objs[i];
|
||||
while (!cur.is_empty()) {
|
||||
OopAndMarkOop elem = cur.pop();
|
||||
elem.set_mark();
|
||||
}
|
||||
cur.clear(true);
|
||||
}
|
||||
_objs_with_preserved_marks.clear(true);
|
||||
_preserved_marks_of_objs.clear(true);
|
||||
|
||||
g1_policy()->phase_times()->record_evac_fail_remove_self_forwards((os::elapsedTime() - remove_self_forwards_start) * 1000.0);
|
||||
}
|
||||
|
||||
void G1CollectedHeap::push_on_evac_failure_scan_stack(oop obj) {
|
||||
_evac_failure_scan_stack->push(obj);
|
||||
}
|
||||
|
||||
void G1CollectedHeap::drain_evac_failure_scan_stack() {
|
||||
assert(_evac_failure_scan_stack != NULL, "precondition");
|
||||
|
||||
while (_evac_failure_scan_stack->length() > 0) {
|
||||
oop obj = _evac_failure_scan_stack->pop();
|
||||
_evac_failure_closure->set_region(heap_region_containing(obj));
|
||||
obj->oop_iterate_backwards(_evac_failure_closure);
|
||||
}
|
||||
}
|
||||
|
||||
oop
|
||||
G1CollectedHeap::handle_evacuation_failure_par(G1ParScanThreadState* _par_scan_state,
|
||||
oop old) {
|
||||
assert(obj_in_cs(old),
|
||||
err_msg("obj: " PTR_FORMAT " should still be in the CSet",
|
||||
p2i(old)));
|
||||
markOop m = old->mark();
|
||||
oop forward_ptr = old->forward_to_atomic(old);
|
||||
if (forward_ptr == NULL) {
|
||||
// Forward-to-self succeeded.
|
||||
assert(_par_scan_state != NULL, "par scan state");
|
||||
OopsInHeapRegionClosure* cl = _par_scan_state->evac_failure_closure();
|
||||
uint queue_num = _par_scan_state->queue_num();
|
||||
|
||||
void G1CollectedHeap::preserve_mark_during_evac_failure(uint queue_num, oop obj, markOop m) {
|
||||
if (!_evacuation_failed) {
|
||||
_evacuation_failed = true;
|
||||
_evacuation_failed_info_array[queue_num].register_copy_failure(old->size());
|
||||
if (_evac_failure_closure != cl) {
|
||||
MutexLockerEx x(EvacFailureStack_lock, Mutex::_no_safepoint_check_flag);
|
||||
assert(!_drain_in_progress,
|
||||
"Should only be true while someone holds the lock.");
|
||||
// Set the global evac-failure closure to the current thread's.
|
||||
assert(_evac_failure_closure == NULL, "Or locking has failed.");
|
||||
set_evac_failure_closure(cl);
|
||||
// Now do the common part.
|
||||
handle_evacuation_failure_common(old, m);
|
||||
// Reset to NULL.
|
||||
set_evac_failure_closure(NULL);
|
||||
} else {
|
||||
// The lock is already held, and this is recursive.
|
||||
assert(_drain_in_progress, "This should only be the recursive case.");
|
||||
handle_evacuation_failure_common(old, m);
|
||||
}
|
||||
return old;
|
||||
} else {
|
||||
// Forward-to-self failed. Either someone else managed to allocate
|
||||
// space for this object (old != forward_ptr) or they beat us in
|
||||
// self-forwarding it (old == forward_ptr).
|
||||
assert(old == forward_ptr || !obj_in_cs(forward_ptr),
|
||||
err_msg("obj: " PTR_FORMAT " forwarded to: " PTR_FORMAT " "
|
||||
"should not be in the CSet",
|
||||
p2i(old), p2i(forward_ptr)));
|
||||
return forward_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void G1CollectedHeap::handle_evacuation_failure_common(oop old, markOop m) {
|
||||
preserve_mark_if_necessary(old, m);
|
||||
|
||||
HeapRegion* r = heap_region_containing(old);
|
||||
if (!r->evacuation_failed()) {
|
||||
r->set_evacuation_failed(true);
|
||||
_hr_printer.evac_failure(r);
|
||||
}
|
||||
|
||||
push_on_evac_failure_scan_stack(old);
|
||||
_evacuation_failed_info_array[queue_num].register_copy_failure(obj->size());
|
||||
|
||||
if (!_drain_in_progress) {
|
||||
// prevent recursion in copy_to_survivor_space()
|
||||
_drain_in_progress = true;
|
||||
drain_evac_failure_scan_stack();
|
||||
_drain_in_progress = false;
|
||||
}
|
||||
}
|
||||
|
||||
void G1CollectedHeap::preserve_mark_if_necessary(oop obj, markOop m) {
|
||||
assert(evacuation_failed(), "Oversaving!");
|
||||
// We want to call the "for_promotion_failure" version only in the
|
||||
// case of a promotion failure.
|
||||
if (m->must_be_preserved_for_promotion_failure(obj)) {
|
||||
_objs_with_preserved_marks.push(obj);
|
||||
_preserved_marks_of_objs.push(m);
|
||||
OopAndMarkOop elem(obj, m);
|
||||
_preserved_objs[queue_num].push(elem);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4450,15 +4366,8 @@ void G1ParCopyClosure<barrier, do_mark_object>::do_oop_work(T* p) {
|
||||
mark_object(obj);
|
||||
}
|
||||
}
|
||||
|
||||
if (barrier == G1BarrierEvac) {
|
||||
_par_scan_state->update_rs(_from, p, _worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
template void G1ParCopyClosure<G1BarrierEvac, G1MarkNone>::do_oop_work(oop* p);
|
||||
template void G1ParCopyClosure<G1BarrierEvac, G1MarkNone>::do_oop_work(narrowOop* p);
|
||||
|
||||
class G1ParEvacuateFollowersClosure : public VoidClosure {
|
||||
protected:
|
||||
G1CollectedHeap* _g1h;
|
||||
@ -4597,9 +4506,6 @@ public:
|
||||
ReferenceProcessor* rp = _g1h->ref_processor_stw();
|
||||
|
||||
G1ParScanThreadState pss(_g1h, worker_id, rp);
|
||||
G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, rp);
|
||||
|
||||
pss.set_evac_failure_closure(&evac_failure_cl);
|
||||
|
||||
bool only_young = _g1h->collector_state()->gcs_are_young();
|
||||
|
||||
@ -5269,9 +5175,6 @@ public:
|
||||
G1STWIsAliveClosure is_alive(_g1h);
|
||||
|
||||
G1ParScanThreadState pss(_g1h, worker_id, NULL);
|
||||
G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL);
|
||||
|
||||
pss.set_evac_failure_closure(&evac_failure_cl);
|
||||
|
||||
G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, &pss, NULL);
|
||||
|
||||
@ -5368,10 +5271,6 @@ public:
|
||||
HandleMark hm;
|
||||
|
||||
G1ParScanThreadState pss(_g1h, worker_id, NULL);
|
||||
G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL);
|
||||
|
||||
pss.set_evac_failure_closure(&evac_failure_cl);
|
||||
|
||||
assert(pss.queue_is_empty(), "both queue and overflow should be empty");
|
||||
|
||||
G1ParScanExtRootClosure only_copy_non_heap_cl(_g1h, &pss, NULL);
|
||||
@ -5476,15 +5375,11 @@ void G1CollectedHeap::process_discovered_references() {
|
||||
|
||||
// Use only a single queue for this PSS.
|
||||
G1ParScanThreadState pss(this, 0, NULL);
|
||||
assert(pss.queue_is_empty(), "pre-condition");
|
||||
|
||||
// We do not embed a reference processor in the copying/scanning
|
||||
// closures while we're actually processing the discovered
|
||||
// reference objects.
|
||||
G1ParScanHeapEvacFailureClosure evac_failure_cl(this, &pss, NULL);
|
||||
|
||||
pss.set_evac_failure_closure(&evac_failure_cl);
|
||||
|
||||
assert(pss.queue_is_empty(), "pre-condition");
|
||||
|
||||
G1ParScanExtRootClosure only_copy_non_heap_cl(this, &pss, NULL);
|
||||
|
||||
@ -5590,8 +5485,6 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
|
||||
|
||||
const uint n_workers = workers()->active_workers();
|
||||
|
||||
init_for_evac_failure(NULL);
|
||||
|
||||
assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty");
|
||||
double start_par_time_sec = os::elapsedTime();
|
||||
double end_par_time_sec;
|
||||
@ -5655,8 +5548,6 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
|
||||
|
||||
purge_code_root_memory();
|
||||
|
||||
finalize_for_evac_failure();
|
||||
|
||||
if (evacuation_failed()) {
|
||||
remove_self_forwarding_pointers();
|
||||
|
||||
@ -5745,7 +5636,7 @@ void G1CollectedHeap::prepend_to_freelist(FreeRegionList* list) {
|
||||
}
|
||||
|
||||
void G1CollectedHeap::decrement_summary_bytes(size_t bytes) {
|
||||
_allocator->decrease_used(bytes);
|
||||
decrease_used(bytes);
|
||||
}
|
||||
|
||||
class G1ParCleanupCTTask : public AbstractGangTask {
|
||||
@ -6395,6 +6286,21 @@ void G1CollectedHeap::tear_down_region_sets(bool free_list_only) {
|
||||
_hrm.remove_all_free_regions();
|
||||
}
|
||||
|
||||
void G1CollectedHeap::increase_used(size_t bytes) {
|
||||
_summary_bytes_used += bytes;
|
||||
}
|
||||
|
||||
void G1CollectedHeap::decrease_used(size_t bytes) {
|
||||
assert(_summary_bytes_used >= bytes,
|
||||
err_msg("invariant: _summary_bytes_used: " SIZE_FORMAT " should be >= bytes: " SIZE_FORMAT,
|
||||
_summary_bytes_used, bytes));
|
||||
_summary_bytes_used -= bytes;
|
||||
}
|
||||
|
||||
void G1CollectedHeap::set_used(size_t bytes) {
|
||||
_summary_bytes_used = bytes;
|
||||
}
|
||||
|
||||
class RebuildRegionSetsClosure : public HeapRegionClosure {
|
||||
private:
|
||||
bool _free_list_only;
|
||||
@ -6463,15 +6369,15 @@ void G1CollectedHeap::rebuild_region_sets(bool free_list_only) {
|
||||
heap_region_iterate(&cl);
|
||||
|
||||
if (!free_list_only) {
|
||||
_allocator->set_used(cl.total_used());
|
||||
set_used(cl.total_used());
|
||||
if (_archive_allocator != NULL) {
|
||||
_archive_allocator->clear_used();
|
||||
}
|
||||
}
|
||||
assert(_allocator->used_unlocked() == recalculate_used(),
|
||||
err_msg("inconsistent _allocator->used_unlocked(), "
|
||||
assert(used_unlocked() == recalculate_used(),
|
||||
err_msg("inconsistent used_unlocked(), "
|
||||
"value: " SIZE_FORMAT " recalculated: " SIZE_FORMAT,
|
||||
_allocator->used_unlocked(), recalculate_used()));
|
||||
used_unlocked(), recalculate_used()));
|
||||
}
|
||||
|
||||
void G1CollectedHeap::set_refine_cte_cl_concurrency(bool concurrent) {
|
||||
@ -6511,7 +6417,7 @@ void G1CollectedHeap::retire_mutator_alloc_region(HeapRegion* alloc_region,
|
||||
assert(alloc_region->is_eden(), "all mutator alloc regions should be eden");
|
||||
|
||||
g1_policy()->add_region_to_incremental_cset_lhs(alloc_region);
|
||||
_allocator->increase_used(allocated_bytes);
|
||||
increase_used(allocated_bytes);
|
||||
_hr_printer.retire(alloc_region);
|
||||
// We update the eden sizes here, when the region is retired,
|
||||
// instead of when it's allocated, since this is the point that its
|
||||
|
@ -251,6 +251,15 @@ private:
|
||||
// Class that handles the different kinds of allocations.
|
||||
G1Allocator* _allocator;
|
||||
|
||||
// Outside of GC pauses, the number of bytes used in all regions other
|
||||
// than the current allocation region(s).
|
||||
size_t _summary_bytes_used;
|
||||
|
||||
void increase_used(size_t bytes);
|
||||
void decrease_used(size_t bytes);
|
||||
|
||||
void set_used(size_t bytes);
|
||||
|
||||
// Class that handles archive allocation ranges.
|
||||
G1ArchiveAllocator* _archive_allocator;
|
||||
|
||||
@ -858,44 +867,27 @@ protected:
|
||||
// forwarding pointers to themselves. Reset them.
|
||||
void remove_self_forwarding_pointers();
|
||||
|
||||
// Together, these store an object with a preserved mark, and its mark value.
|
||||
Stack<oop, mtGC> _objs_with_preserved_marks;
|
||||
Stack<markOop, mtGC> _preserved_marks_of_objs;
|
||||
struct OopAndMarkOop {
|
||||
private:
|
||||
oop _o;
|
||||
markOop _m;
|
||||
public:
|
||||
OopAndMarkOop(oop obj, markOop m) : _o(obj), _m(m) {
|
||||
}
|
||||
|
||||
void set_mark() {
|
||||
_o->set_mark(_m);
|
||||
}
|
||||
};
|
||||
|
||||
typedef Stack<OopAndMarkOop,mtGC> OopAndMarkOopStack;
|
||||
// Stores marks with the corresponding oop that we need to preserve during evacuation
|
||||
// failure.
|
||||
OopAndMarkOopStack* _preserved_objs;
|
||||
|
||||
// Preserve the mark of "obj", if necessary, in preparation for its mark
|
||||
// word being overwritten with a self-forwarding-pointer.
|
||||
void preserve_mark_if_necessary(oop obj, markOop m);
|
||||
|
||||
// The stack of evac-failure objects left to be scanned.
|
||||
GrowableArray<oop>* _evac_failure_scan_stack;
|
||||
// The closure to apply to evac-failure objects.
|
||||
|
||||
OopsInHeapRegionClosure* _evac_failure_closure;
|
||||
// Set the field above.
|
||||
void
|
||||
set_evac_failure_closure(OopsInHeapRegionClosure* evac_failure_closure) {
|
||||
_evac_failure_closure = evac_failure_closure;
|
||||
}
|
||||
|
||||
// Push "obj" on the scan stack.
|
||||
void push_on_evac_failure_scan_stack(oop obj);
|
||||
// Process scan stack entries until the stack is empty.
|
||||
void drain_evac_failure_scan_stack();
|
||||
// True iff an invocation of "drain_scan_stack" is in progress; to
|
||||
// prevent unnecessary recursion.
|
||||
bool _drain_in_progress;
|
||||
|
||||
// Do any necessary initialization for evacuation-failure handling.
|
||||
// "cl" is the closure that will be used to process evac-failure
|
||||
// objects.
|
||||
void init_for_evac_failure(OopsInHeapRegionClosure* cl);
|
||||
// Do any necessary cleanup for evacuation-failure handling data
|
||||
// structures.
|
||||
void finalize_for_evac_failure();
|
||||
|
||||
// An attempt to evacuate "obj" has failed; take necessary steps.
|
||||
oop handle_evacuation_failure_par(G1ParScanThreadState* _par_scan_state, oop obj);
|
||||
void handle_evacuation_failure_common(oop obj, markOop m);
|
||||
void preserve_mark_during_evac_failure(uint queue, oop obj, markOop m);
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Support for forcing evacuation failures. Analogous to
|
||||
|
@ -111,7 +111,6 @@ protected:
|
||||
|
||||
enum G1Barrier {
|
||||
G1BarrierNone,
|
||||
G1BarrierEvac,
|
||||
G1BarrierKlass
|
||||
};
|
||||
|
||||
@ -148,8 +147,6 @@ typedef G1ParCopyClosure<G1BarrierNone, G1MarkPromotedFromRoot> G1ParScanAndMar
|
||||
// We use a separate closure to handle references during evacuation
|
||||
// failure processing.
|
||||
|
||||
typedef G1ParCopyClosure<G1BarrierEvac, G1MarkNone> G1ParScanHeapEvacFailureClosure;
|
||||
|
||||
class FilterIntoCSClosure: public ExtendedOopClosure {
|
||||
G1CollectedHeap* _g1;
|
||||
OopClosure* _oc;
|
||||
|
@ -144,8 +144,6 @@ bool G1ParScanThreadState::verify_task(StarTask ref) const {
|
||||
#endif // ASSERT
|
||||
|
||||
void G1ParScanThreadState::trim_queue() {
|
||||
assert(_evac_failure_cl != NULL, "not set");
|
||||
|
||||
StarTask ref;
|
||||
do {
|
||||
// Drain the overflow stack first, so other threads can steal.
|
||||
@ -222,7 +220,7 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
|
||||
if (obj_ptr == NULL) {
|
||||
// This will either forward-to-self, or detect that someone else has
|
||||
// installed a forwarding pointer.
|
||||
return _g1h->handle_evacuation_failure_par(this, old);
|
||||
return handle_evacuation_failure_par(old, old_mark);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -236,7 +234,7 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
|
||||
// Doing this after all the allocation attempts also tests the
|
||||
// undo_allocation() method too.
|
||||
_g1_par_allocator->undo_allocation(dest_state, obj_ptr, word_sz, context);
|
||||
return _g1h->handle_evacuation_failure_par(this, old);
|
||||
return handle_evacuation_failure_par(old, old_mark);
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
||||
@ -301,3 +299,36 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state,
|
||||
return forward_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markOop m) {
|
||||
assert(_g1h->obj_in_cs(old),
|
||||
err_msg("Object " PTR_FORMAT " should be in the CSet", p2i(old)));
|
||||
|
||||
oop forward_ptr = old->forward_to_atomic(old);
|
||||
if (forward_ptr == NULL) {
|
||||
// Forward-to-self succeeded. We are the "owner" of the object.
|
||||
HeapRegion* r = _g1h->heap_region_containing(old);
|
||||
|
||||
if (!r->evacuation_failed()) {
|
||||
r->set_evacuation_failed(true);
|
||||
_g1h->hr_printer()->evac_failure(r);
|
||||
}
|
||||
|
||||
_g1h->preserve_mark_during_evac_failure(_queue_num, old, m);
|
||||
|
||||
_scanner.set_region(r);
|
||||
old->oop_iterate_backwards(&_scanner);
|
||||
|
||||
return old;
|
||||
} else {
|
||||
// Forward-to-self failed. Either someone else managed to allocate
|
||||
// space for this object (old != forward_ptr) or they beat us in
|
||||
// self-forwarding it (old == forward_ptr).
|
||||
assert(old == forward_ptr || !_g1h->obj_in_cs(forward_ptr),
|
||||
err_msg("Object " PTR_FORMAT " forwarded to: " PTR_FORMAT " "
|
||||
"should not be in the CSet",
|
||||
p2i(old), p2i(forward_ptr)));
|
||||
return forward_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,8 +54,6 @@ class G1ParScanThreadState : public StackObj {
|
||||
uint _tenuring_threshold;
|
||||
G1ParScanClosure _scanner;
|
||||
|
||||
OopsInHeapRegionClosure* _evac_failure_cl;
|
||||
|
||||
int _hash_seed;
|
||||
uint _queue_num;
|
||||
|
||||
@ -114,12 +112,6 @@ class G1ParScanThreadState : public StackObj {
|
||||
}
|
||||
}
|
||||
|
||||
void set_evac_failure_closure(OopsInHeapRegionClosure* evac_failure_cl) {
|
||||
_evac_failure_cl = evac_failure_cl;
|
||||
}
|
||||
|
||||
OopsInHeapRegionClosure* evac_failure_closure() { return _evac_failure_cl; }
|
||||
|
||||
int* hash_seed() { return &_hash_seed; }
|
||||
uint queue_num() { return _queue_num; }
|
||||
|
||||
@ -211,6 +203,9 @@ class G1ParScanThreadState : public StackObj {
|
||||
void trim_queue();
|
||||
|
||||
inline void steal_and_trim_queue(RefToScanQueueSet *task_queues);
|
||||
|
||||
// An attempt to evacuate "obj" has failed; take necessary steps.
|
||||
oop handle_evacuation_failure_par(oop obj, markOop m);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_G1_G1PARSCANTHREADSTATE_HPP
|
||||
|
@ -45,13 +45,11 @@
|
||||
nonstatic_field(HeapRegionManager, _regions, G1HeapRegionTable) \
|
||||
nonstatic_field(HeapRegionManager, _num_committed, uint) \
|
||||
\
|
||||
nonstatic_field(G1Allocator, _summary_bytes_used, size_t) \
|
||||
\
|
||||
nonstatic_field(G1CollectedHeap, _summary_bytes_used, size_t) \
|
||||
nonstatic_field(G1CollectedHeap, _hrm, HeapRegionManager) \
|
||||
nonstatic_field(G1CollectedHeap, _g1mm, G1MonitoringSupport*) \
|
||||
nonstatic_field(G1CollectedHeap, _old_set, HeapRegionSetBase) \
|
||||
nonstatic_field(G1CollectedHeap, _humongous_set, HeapRegionSetBase) \
|
||||
nonstatic_field(G1CollectedHeap, _allocator, G1Allocator*) \
|
||||
\
|
||||
nonstatic_field(G1MonitoringSupport, _eden_committed, size_t) \
|
||||
nonstatic_field(G1MonitoringSupport, _eden_used, size_t) \
|
||||
@ -78,12 +76,10 @@
|
||||
declare_toplevel_type(HeapRegionSetBase) \
|
||||
declare_toplevel_type(HeapRegionSetCount) \
|
||||
declare_toplevel_type(G1MonitoringSupport) \
|
||||
declare_toplevel_type(G1Allocator) \
|
||||
\
|
||||
declare_toplevel_type(G1CollectedHeap*) \
|
||||
declare_toplevel_type(HeapRegion*) \
|
||||
declare_toplevel_type(G1MonitoringSupport*) \
|
||||
declare_toplevel_type(G1Allocator*) \
|
||||
|
||||
|
||||
#endif // SHARE_VM_GC_G1_VMSTRUCTS_G1_HPP
|
||||
|
@ -40,7 +40,6 @@ class CheckForUnmarkedOops : public OopClosure {
|
||||
PSYoungGen* _young_gen;
|
||||
CardTableExtension* _card_table;
|
||||
HeapWord* _unmarked_addr;
|
||||
jbyte* _unmarked_card;
|
||||
|
||||
protected:
|
||||
template <class T> void do_oop_work(T* p) {
|
||||
@ -50,7 +49,6 @@ class CheckForUnmarkedOops : public OopClosure {
|
||||
// Don't overwrite the first missing card mark
|
||||
if (_unmarked_addr == NULL) {
|
||||
_unmarked_addr = (HeapWord*)p;
|
||||
_unmarked_card = _card_table->byte_for(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -623,7 +623,7 @@ void DefNewGeneration::collect(bool full,
|
||||
{
|
||||
// DefNew needs to run with n_threads == 0, to make sure the serial
|
||||
// version of the card table scanning code is used.
|
||||
// See: CardTableModRefBS::non_clean_card_iterate_possibly_parallel.
|
||||
// See: CardTableModRefBSForCTRS::non_clean_card_iterate_possibly_parallel.
|
||||
StrongRootsScope srs(0);
|
||||
|
||||
gch->gen_process_roots(&srs,
|
||||
|
@ -24,22 +24,12 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/cardTableModRefBS.inline.hpp"
|
||||
#include "gc/shared/cardTableRS.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
#include "gc/shared/space.hpp"
|
||||
#include "gc/shared/space.inline.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "memory/virtualspace.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#ifdef COMPILER1
|
||||
#include "c1/c1_LIR.hpp"
|
||||
#include "c1/c1_LIRGenerator.hpp"
|
||||
#endif
|
||||
|
||||
// This kind of "BarrierSet" allows a "CollectedHeap" to detect and
|
||||
// enumerate ref fields that have been modified (since the last
|
||||
@ -68,12 +58,7 @@ CardTableModRefBS::CardTableModRefBS(
|
||||
_committed(NULL),
|
||||
_cur_covered_regions(0),
|
||||
_byte_map(NULL),
|
||||
byte_map_base(NULL),
|
||||
// LNC functionality
|
||||
_lowest_non_clean(NULL),
|
||||
_lowest_non_clean_chunk_size(NULL),
|
||||
_lowest_non_clean_base_chunk_index(NULL),
|
||||
_last_LNC_resizing_collection(NULL)
|
||||
byte_map_base(NULL)
|
||||
{
|
||||
assert((uintptr_t(_whole_heap.start()) & (card_size - 1)) == 0, "heap must start at card boundary");
|
||||
assert((uintptr_t(_whole_heap.end()) & (card_size - 1)) == 0, "heap must end at card boundary");
|
||||
@ -130,25 +115,6 @@ void CardTableModRefBS::initialize() {
|
||||
!ExecMem, "card table last card");
|
||||
*guard_card = last_card;
|
||||
|
||||
_lowest_non_clean =
|
||||
NEW_C_HEAP_ARRAY(CardArr, _max_covered_regions, mtGC);
|
||||
_lowest_non_clean_chunk_size =
|
||||
NEW_C_HEAP_ARRAY(size_t, _max_covered_regions, mtGC);
|
||||
_lowest_non_clean_base_chunk_index =
|
||||
NEW_C_HEAP_ARRAY(uintptr_t, _max_covered_regions, mtGC);
|
||||
_last_LNC_resizing_collection =
|
||||
NEW_C_HEAP_ARRAY(int, _max_covered_regions, mtGC);
|
||||
if (_lowest_non_clean == NULL
|
||||
|| _lowest_non_clean_chunk_size == NULL
|
||||
|| _lowest_non_clean_base_chunk_index == NULL
|
||||
|| _last_LNC_resizing_collection == NULL)
|
||||
vm_exit_during_initialization("couldn't allocate an LNC array.");
|
||||
for (int i = 0; i < _max_covered_regions; i++) {
|
||||
_lowest_non_clean[i] = NULL;
|
||||
_lowest_non_clean_chunk_size[i] = 0;
|
||||
_last_LNC_resizing_collection[i] = -1;
|
||||
}
|
||||
|
||||
if (TraceCardTableModRefBS) {
|
||||
gclog_or_tty->print_cr("CardTableModRefBS::CardTableModRefBS: ");
|
||||
gclog_or_tty->print_cr(" "
|
||||
@ -171,22 +137,6 @@ CardTableModRefBS::~CardTableModRefBS() {
|
||||
delete[] _committed;
|
||||
_committed = NULL;
|
||||
}
|
||||
if (_lowest_non_clean) {
|
||||
FREE_C_HEAP_ARRAY(CardArr, _lowest_non_clean);
|
||||
_lowest_non_clean = NULL;
|
||||
}
|
||||
if (_lowest_non_clean_chunk_size) {
|
||||
FREE_C_HEAP_ARRAY(size_t, _lowest_non_clean_chunk_size);
|
||||
_lowest_non_clean_chunk_size = NULL;
|
||||
}
|
||||
if (_lowest_non_clean_base_chunk_index) {
|
||||
FREE_C_HEAP_ARRAY(uintptr_t, _lowest_non_clean_base_chunk_index);
|
||||
_lowest_non_clean_base_chunk_index = NULL;
|
||||
}
|
||||
if (_last_LNC_resizing_collection) {
|
||||
FREE_C_HEAP_ARRAY(int, _last_LNC_resizing_collection);
|
||||
_last_LNC_resizing_collection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int CardTableModRefBS::find_covering_region_by_base(HeapWord* base) {
|
||||
@ -437,32 +387,6 @@ void CardTableModRefBS::write_ref_field_work(void* field, oop newVal, bool relea
|
||||
}
|
||||
|
||||
|
||||
void CardTableModRefBS::non_clean_card_iterate_possibly_parallel(Space* sp,
|
||||
MemRegion mr,
|
||||
OopsInGenClosure* cl,
|
||||
CardTableRS* ct,
|
||||
uint n_threads) {
|
||||
if (!mr.is_empty()) {
|
||||
if (n_threads > 0) {
|
||||
#if INCLUDE_ALL_GCS
|
||||
non_clean_card_iterate_parallel_work(sp, mr, cl, ct, n_threads);
|
||||
#else // INCLUDE_ALL_GCS
|
||||
fatal("Parallel gc not supported here.");
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
} else {
|
||||
// clear_cl finds contiguous dirty ranges of cards to process and clear.
|
||||
|
||||
// This is the single-threaded version used by DefNew.
|
||||
const bool parallel = false;
|
||||
|
||||
DirtyCardToOopClosure* dcto_cl = sp->new_dcto_cl(cl, precision(), cl->gen_boundary(), parallel);
|
||||
ClearNoncleanCardWrapper clear_cl(dcto_cl, ct, parallel);
|
||||
|
||||
clear_cl.do_MemRegion(mr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardTableModRefBS::dirty_MemRegion(MemRegion mr) {
|
||||
assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start");
|
||||
assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" );
|
||||
@ -623,15 +547,3 @@ void CardTableModRefBS::print_on(outputStream* st) const {
|
||||
p2i(_byte_map), p2i(_byte_map + _byte_map_size), p2i(byte_map_base));
|
||||
}
|
||||
|
||||
bool CardTableModRefBSForCTRS::card_will_be_scanned(jbyte cv) {
|
||||
return
|
||||
CardTableModRefBS::card_will_be_scanned(cv) ||
|
||||
_rs->is_prev_nonclean_card_val(cv);
|
||||
};
|
||||
|
||||
bool CardTableModRefBSForCTRS::card_may_have_been_dirty(jbyte cv) {
|
||||
return
|
||||
cv != clean_card &&
|
||||
(CardTableModRefBS::card_may_have_been_dirty(cv) ||
|
||||
CardTableRS::youngergen_may_have_been_dirty(cv));
|
||||
};
|
||||
|
@ -40,23 +40,9 @@
|
||||
// Closures used to scan dirty cards should take these
|
||||
// considerations into account.
|
||||
|
||||
class Generation;
|
||||
class OopsInGenClosure;
|
||||
class DirtyCardToOopClosure;
|
||||
class ClearNoncleanCardWrapper;
|
||||
class CardTableRS;
|
||||
|
||||
class CardTableModRefBS: public ModRefBarrierSet {
|
||||
// Some classes get to look at some private stuff.
|
||||
friend class BytecodeInterpreter;
|
||||
friend class VMStructs;
|
||||
friend class CardTableRS;
|
||||
friend class CheckForUnmarkedOops; // Needs access to raw card bytes.
|
||||
friend class SharkBuilder;
|
||||
#ifndef PRODUCT
|
||||
// For debugging.
|
||||
friend class GuaranteeNotModClosure;
|
||||
#endif
|
||||
protected:
|
||||
|
||||
enum CardValues {
|
||||
@ -75,24 +61,6 @@ class CardTableModRefBS: public ModRefBarrierSet {
|
||||
// a word's worth (row) of clean card values
|
||||
static const intptr_t clean_card_row = (intptr_t)(-1);
|
||||
|
||||
// dirty and precleaned are equivalent wrt younger_refs_iter.
|
||||
static bool card_is_dirty_wrt_gen_iter(jbyte cv) {
|
||||
return cv == dirty_card || cv == precleaned_card;
|
||||
}
|
||||
|
||||
// Returns "true" iff the value "cv" will cause the card containing it
|
||||
// to be scanned in the current traversal. May be overridden by
|
||||
// subtypes.
|
||||
virtual bool card_will_be_scanned(jbyte cv) {
|
||||
return CardTableModRefBS::card_is_dirty_wrt_gen_iter(cv);
|
||||
}
|
||||
|
||||
// Returns "true" iff the value "cv" may have represented a dirty card at
|
||||
// some point.
|
||||
virtual bool card_may_have_been_dirty(jbyte cv) {
|
||||
return card_is_dirty_wrt_gen_iter(cv);
|
||||
}
|
||||
|
||||
// The declaration order of these const fields is important; see the
|
||||
// constructor before changing.
|
||||
const MemRegion _whole_heap; // the region covered by the card table
|
||||
@ -174,20 +142,6 @@ class CardTableModRefBS: public ModRefBarrierSet {
|
||||
return byte_for(p) + 1;
|
||||
}
|
||||
|
||||
// Iterate over the portion of the card-table which covers the given
|
||||
// region mr in the given space and apply cl to any dirty sub-regions
|
||||
// of mr. Clears the dirty cards as they are processed.
|
||||
void non_clean_card_iterate_possibly_parallel(Space* sp, MemRegion mr,
|
||||
OopsInGenClosure* cl, CardTableRS* ct,
|
||||
uint n_threads);
|
||||
|
||||
private:
|
||||
// Work method used to implement non_clean_card_iterate_possibly_parallel()
|
||||
// above in the parallel case.
|
||||
void non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
|
||||
OopsInGenClosure* cl, CardTableRS* ct,
|
||||
uint n_threads);
|
||||
|
||||
protected:
|
||||
// Dirty the bytes corresponding to "mr" (not all of which must be
|
||||
// covered.)
|
||||
@ -197,65 +151,6 @@ class CardTableModRefBS: public ModRefBarrierSet {
|
||||
// all of which must be covered.)
|
||||
void clear_MemRegion(MemRegion mr);
|
||||
|
||||
// *** Support for parallel card scanning.
|
||||
|
||||
// This is an array, one element per covered region of the card table.
|
||||
// Each entry is itself an array, with one element per chunk in the
|
||||
// covered region. Each entry of these arrays is the lowest non-clean
|
||||
// card of the corresponding chunk containing part of an object from the
|
||||
// previous chunk, or else NULL.
|
||||
typedef jbyte* CardPtr;
|
||||
typedef CardPtr* CardArr;
|
||||
CardArr* _lowest_non_clean;
|
||||
size_t* _lowest_non_clean_chunk_size;
|
||||
uintptr_t* _lowest_non_clean_base_chunk_index;
|
||||
int* _last_LNC_resizing_collection;
|
||||
|
||||
// Initializes "lowest_non_clean" to point to the array for the region
|
||||
// covering "sp", and "lowest_non_clean_base_chunk_index" to the chunk
|
||||
// index of the corresponding to the first element of that array.
|
||||
// Ensures that these arrays are of sufficient size, allocating if necessary.
|
||||
// May be called by several threads concurrently.
|
||||
void get_LNC_array_for_space(Space* sp,
|
||||
jbyte**& lowest_non_clean,
|
||||
uintptr_t& lowest_non_clean_base_chunk_index,
|
||||
size_t& lowest_non_clean_chunk_size);
|
||||
|
||||
// Returns the number of chunks necessary to cover "mr".
|
||||
size_t chunks_to_cover(MemRegion mr) {
|
||||
return (size_t)(addr_to_chunk_index(mr.last()) -
|
||||
addr_to_chunk_index(mr.start()) + 1);
|
||||
}
|
||||
|
||||
// Returns the index of the chunk in a stride which
|
||||
// covers the given address.
|
||||
uintptr_t addr_to_chunk_index(const void* addr) {
|
||||
uintptr_t card = (uintptr_t) byte_for(addr);
|
||||
return card / ParGCCardsPerStrideChunk;
|
||||
}
|
||||
|
||||
// Apply cl, which must either itself apply dcto_cl or be dcto_cl,
|
||||
// to the cards in the stride (of n_strides) within the given space.
|
||||
void process_stride(Space* sp,
|
||||
MemRegion used,
|
||||
jint stride, int n_strides,
|
||||
OopsInGenClosure* cl,
|
||||
CardTableRS* ct,
|
||||
jbyte** lowest_non_clean,
|
||||
uintptr_t lowest_non_clean_base_chunk_index,
|
||||
size_t lowest_non_clean_chunk_size);
|
||||
|
||||
// Makes sure that chunk boundaries are handled appropriately, by
|
||||
// adjusting the min_done of dcto_cl, and by using a special card-table
|
||||
// value to indicate how min_done should be set.
|
||||
void process_chunk_boundaries(Space* sp,
|
||||
DirtyCardToOopClosure* dcto_cl,
|
||||
MemRegion chunk_mr,
|
||||
MemRegion used,
|
||||
jbyte** lowest_non_clean,
|
||||
uintptr_t lowest_non_clean_base_chunk_index,
|
||||
size_t lowest_non_clean_chunk_size);
|
||||
|
||||
public:
|
||||
// Constants
|
||||
enum SomePublicConstants {
|
||||
@ -436,34 +331,5 @@ struct BarrierSet::GetName<CardTableModRefBS> {
|
||||
static const BarrierSet::Name value = BarrierSet::CardTableModRef;
|
||||
};
|
||||
|
||||
class CardTableRS;
|
||||
|
||||
// A specialization for the CardTableRS gen rem set.
|
||||
class CardTableModRefBSForCTRS: public CardTableModRefBS {
|
||||
CardTableRS* _rs;
|
||||
protected:
|
||||
bool card_will_be_scanned(jbyte cv);
|
||||
bool card_may_have_been_dirty(jbyte cv);
|
||||
public:
|
||||
CardTableModRefBSForCTRS(MemRegion whole_heap) :
|
||||
CardTableModRefBS(
|
||||
whole_heap,
|
||||
// Concrete tag should be BarrierSet::CardTableForRS.
|
||||
// That will presently break things in a bunch of places though.
|
||||
// The concrete tag is used as a dispatch key in many places, and
|
||||
// CardTableForRS does not correctly dispatch in some of those
|
||||
// uses. This will be addressed as part of a reorganization of the
|
||||
// BarrierSet hierarchy.
|
||||
BarrierSet::FakeRtti(BarrierSet::CardTableModRef, 0).add_tag(BarrierSet::CardTableForRS))
|
||||
{}
|
||||
|
||||
void set_CTRS(CardTableRS* rs) { _rs = rs; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct BarrierSet::GetName<CardTableModRefBSForCTRS> {
|
||||
static const BarrierSet::Name value = BarrierSet::CardTableForRS;
|
||||
};
|
||||
|
||||
|
||||
#endif // SHARE_VM_GC_SHARED_CARDTABLEMODREFBS_HPP
|
||||
|
129
hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.cpp
Normal file
129
hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/cardTableModRefBS.inline.hpp"
|
||||
#include "gc/shared/cardTableRS.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "gc/shared/space.inline.hpp"
|
||||
|
||||
CardTableModRefBSForCTRS::CardTableModRefBSForCTRS(MemRegion whole_heap) :
|
||||
CardTableModRefBS(
|
||||
whole_heap,
|
||||
// Concrete tag should be BarrierSet::CardTableForRS.
|
||||
// That will presently break things in a bunch of places though.
|
||||
// The concrete tag is used as a dispatch key in many places, and
|
||||
// CardTableForRS does not correctly dispatch in some of those
|
||||
// uses. This will be addressed as part of a reorganization of the
|
||||
// BarrierSet hierarchy.
|
||||
BarrierSet::FakeRtti(BarrierSet::CardTableModRef, 0).add_tag(BarrierSet::CardTableForRS)),
|
||||
// LNC functionality
|
||||
_lowest_non_clean(NULL),
|
||||
_lowest_non_clean_chunk_size(NULL),
|
||||
_lowest_non_clean_base_chunk_index(NULL),
|
||||
_last_LNC_resizing_collection(NULL)
|
||||
{ }
|
||||
|
||||
void CardTableModRefBSForCTRS::initialize() {
|
||||
CardTableModRefBS::initialize();
|
||||
_lowest_non_clean =
|
||||
NEW_C_HEAP_ARRAY(CardArr, _max_covered_regions, mtGC);
|
||||
_lowest_non_clean_chunk_size =
|
||||
NEW_C_HEAP_ARRAY(size_t, _max_covered_regions, mtGC);
|
||||
_lowest_non_clean_base_chunk_index =
|
||||
NEW_C_HEAP_ARRAY(uintptr_t, _max_covered_regions, mtGC);
|
||||
_last_LNC_resizing_collection =
|
||||
NEW_C_HEAP_ARRAY(int, _max_covered_regions, mtGC);
|
||||
if (_lowest_non_clean == NULL
|
||||
|| _lowest_non_clean_chunk_size == NULL
|
||||
|| _lowest_non_clean_base_chunk_index == NULL
|
||||
|| _last_LNC_resizing_collection == NULL)
|
||||
vm_exit_during_initialization("couldn't allocate an LNC array.");
|
||||
for (int i = 0; i < _max_covered_regions; i++) {
|
||||
_lowest_non_clean[i] = NULL;
|
||||
_lowest_non_clean_chunk_size[i] = 0;
|
||||
_last_LNC_resizing_collection[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
CardTableModRefBSForCTRS::~CardTableModRefBSForCTRS() {
|
||||
if (_lowest_non_clean) {
|
||||
FREE_C_HEAP_ARRAY(CardArr, _lowest_non_clean);
|
||||
_lowest_non_clean = NULL;
|
||||
}
|
||||
if (_lowest_non_clean_chunk_size) {
|
||||
FREE_C_HEAP_ARRAY(size_t, _lowest_non_clean_chunk_size);
|
||||
_lowest_non_clean_chunk_size = NULL;
|
||||
}
|
||||
if (_lowest_non_clean_base_chunk_index) {
|
||||
FREE_C_HEAP_ARRAY(uintptr_t, _lowest_non_clean_base_chunk_index);
|
||||
_lowest_non_clean_base_chunk_index = NULL;
|
||||
}
|
||||
if (_last_LNC_resizing_collection) {
|
||||
FREE_C_HEAP_ARRAY(int, _last_LNC_resizing_collection);
|
||||
_last_LNC_resizing_collection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CardTableModRefBSForCTRS::card_will_be_scanned(jbyte cv) {
|
||||
return
|
||||
card_is_dirty_wrt_gen_iter(cv) ||
|
||||
_rs->is_prev_nonclean_card_val(cv);
|
||||
}
|
||||
|
||||
bool CardTableModRefBSForCTRS::card_may_have_been_dirty(jbyte cv) {
|
||||
return
|
||||
cv != clean_card &&
|
||||
(card_is_dirty_wrt_gen_iter(cv) ||
|
||||
CardTableRS::youngergen_may_have_been_dirty(cv));
|
||||
}
|
||||
|
||||
void CardTableModRefBSForCTRS::non_clean_card_iterate_possibly_parallel(
|
||||
Space* sp,
|
||||
MemRegion mr,
|
||||
OopsInGenClosure* cl,
|
||||
CardTableRS* ct,
|
||||
uint n_threads)
|
||||
{
|
||||
if (!mr.is_empty()) {
|
||||
if (n_threads > 0) {
|
||||
#if INCLUDE_ALL_GCS
|
||||
non_clean_card_iterate_parallel_work(sp, mr, cl, ct, n_threads);
|
||||
#else // INCLUDE_ALL_GCS
|
||||
fatal("Parallel gc not supported here.");
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
} else {
|
||||
// clear_cl finds contiguous dirty ranges of cards to process and clear.
|
||||
|
||||
// This is the single-threaded version used by DefNew.
|
||||
const bool parallel = false;
|
||||
|
||||
DirtyCardToOopClosure* dcto_cl = sp->new_dcto_cl(cl, precision(), cl->gen_boundary(), parallel);
|
||||
ClearNoncleanCardWrapper clear_cl(dcto_cl, ct, parallel);
|
||||
|
||||
clear_cl.do_MemRegion(mr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
143
hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.hpp
Normal file
143
hotspot/src/share/vm/gc/shared/cardTableModRefBSForCTRS.hpp
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_GC_SHARED_CARDTABLEMODREFBSFORCTRS_HPP
|
||||
#define SHARE_VM_GC_SHARED_CARDTABLEMODREFBSFORCTRS_HPP
|
||||
|
||||
#include "gc/shared/cardTableModRefBS.hpp"
|
||||
|
||||
class CardTableRS;
|
||||
class DirtyCardToOopClosure;
|
||||
class OopsInGenClosure;
|
||||
|
||||
// A specialization for the CardTableRS gen rem set.
|
||||
class CardTableModRefBSForCTRS: public CardTableModRefBS {
|
||||
friend class CardTableRS;
|
||||
|
||||
public:
|
||||
CardTableModRefBSForCTRS(MemRegion whole_heap);
|
||||
~CardTableModRefBSForCTRS();
|
||||
|
||||
virtual void initialize();
|
||||
|
||||
void set_CTRS(CardTableRS* rs) { _rs = rs; }
|
||||
|
||||
private:
|
||||
CardTableRS* _rs;
|
||||
|
||||
// *** Support for parallel card scanning.
|
||||
|
||||
// dirty and precleaned are equivalent wrt younger_refs_iter.
|
||||
static bool card_is_dirty_wrt_gen_iter(jbyte cv) {
|
||||
return cv == dirty_card || cv == precleaned_card;
|
||||
}
|
||||
|
||||
// Returns "true" iff the value "cv" will cause the card containing it
|
||||
// to be scanned in the current traversal. May be overridden by
|
||||
// subtypes.
|
||||
bool card_will_be_scanned(jbyte cv);
|
||||
|
||||
// Returns "true" iff the value "cv" may have represented a dirty card at
|
||||
// some point.
|
||||
bool card_may_have_been_dirty(jbyte cv);
|
||||
|
||||
// Iterate over the portion of the card-table which covers the given
|
||||
// region mr in the given space and apply cl to any dirty sub-regions
|
||||
// of mr. Clears the dirty cards as they are processed.
|
||||
void non_clean_card_iterate_possibly_parallel(Space* sp, MemRegion mr,
|
||||
OopsInGenClosure* cl, CardTableRS* ct,
|
||||
uint n_threads);
|
||||
|
||||
// Work method used to implement non_clean_card_iterate_possibly_parallel()
|
||||
// above in the parallel case.
|
||||
void non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
|
||||
OopsInGenClosure* cl, CardTableRS* ct,
|
||||
uint n_threads);
|
||||
|
||||
// This is an array, one element per covered region of the card table.
|
||||
// Each entry is itself an array, with one element per chunk in the
|
||||
// covered region. Each entry of these arrays is the lowest non-clean
|
||||
// card of the corresponding chunk containing part of an object from the
|
||||
// previous chunk, or else NULL.
|
||||
typedef jbyte* CardPtr;
|
||||
typedef CardPtr* CardArr;
|
||||
CardArr* _lowest_non_clean;
|
||||
size_t* _lowest_non_clean_chunk_size;
|
||||
uintptr_t* _lowest_non_clean_base_chunk_index;
|
||||
int* _last_LNC_resizing_collection;
|
||||
|
||||
// Initializes "lowest_non_clean" to point to the array for the region
|
||||
// covering "sp", and "lowest_non_clean_base_chunk_index" to the chunk
|
||||
// index of the corresponding to the first element of that array.
|
||||
// Ensures that these arrays are of sufficient size, allocating if necessary.
|
||||
// May be called by several threads concurrently.
|
||||
void get_LNC_array_for_space(Space* sp,
|
||||
jbyte**& lowest_non_clean,
|
||||
uintptr_t& lowest_non_clean_base_chunk_index,
|
||||
size_t& lowest_non_clean_chunk_size);
|
||||
|
||||
// Returns the number of chunks necessary to cover "mr".
|
||||
size_t chunks_to_cover(MemRegion mr) {
|
||||
return (size_t)(addr_to_chunk_index(mr.last()) -
|
||||
addr_to_chunk_index(mr.start()) + 1);
|
||||
}
|
||||
|
||||
// Returns the index of the chunk in a stride which
|
||||
// covers the given address.
|
||||
uintptr_t addr_to_chunk_index(const void* addr) {
|
||||
uintptr_t card = (uintptr_t) byte_for(addr);
|
||||
return card / ParGCCardsPerStrideChunk;
|
||||
}
|
||||
|
||||
// Apply cl, which must either itself apply dcto_cl or be dcto_cl,
|
||||
// to the cards in the stride (of n_strides) within the given space.
|
||||
void process_stride(Space* sp,
|
||||
MemRegion used,
|
||||
jint stride, int n_strides,
|
||||
OopsInGenClosure* cl,
|
||||
CardTableRS* ct,
|
||||
jbyte** lowest_non_clean,
|
||||
uintptr_t lowest_non_clean_base_chunk_index,
|
||||
size_t lowest_non_clean_chunk_size);
|
||||
|
||||
// Makes sure that chunk boundaries are handled appropriately, by
|
||||
// adjusting the min_done of dcto_cl, and by using a special card-table
|
||||
// value to indicate how min_done should be set.
|
||||
void process_chunk_boundaries(Space* sp,
|
||||
DirtyCardToOopClosure* dcto_cl,
|
||||
MemRegion chunk_mr,
|
||||
MemRegion used,
|
||||
jbyte** lowest_non_clean,
|
||||
uintptr_t lowest_non_clean_base_chunk_index,
|
||||
size_t lowest_non_clean_chunk_size);
|
||||
|
||||
};
|
||||
|
||||
template<>
|
||||
struct BarrierSet::GetName<CardTableModRefBSForCTRS> {
|
||||
static const BarrierSet::Name value = BarrierSet::CardTableForRS;
|
||||
};
|
||||
|
||||
#endif // include guard
|
||||
|
@ -240,7 +240,7 @@ void ClearNoncleanCardWrapper::do_MemRegion(MemRegion mr) {
|
||||
// cur-younger-gen ==> cur_younger_gen
|
||||
// cur_youngergen_and_prev_nonclean_card ==> no change.
|
||||
void CardTableRS::write_ref_field_gc_par(void* field, oop new_val) {
|
||||
jbyte* entry = ct_bs()->byte_for(field);
|
||||
jbyte* entry = _ct_bs->byte_for(field);
|
||||
do {
|
||||
jbyte entry_val = *entry;
|
||||
// We put this first because it's probably the most common case.
|
||||
@ -398,10 +398,10 @@ void CardTableRS::verify_space(Space* s, HeapWord* gen_boundary) {
|
||||
jbyte* cur_entry = byte_for(used.start());
|
||||
jbyte* limit = byte_after(used.last());
|
||||
while (cur_entry < limit) {
|
||||
if (*cur_entry == CardTableModRefBS::clean_card) {
|
||||
if (*cur_entry == clean_card_val()) {
|
||||
jbyte* first_dirty = cur_entry+1;
|
||||
while (first_dirty < limit &&
|
||||
*first_dirty == CardTableModRefBS::clean_card) {
|
||||
*first_dirty == clean_card_val()) {
|
||||
first_dirty++;
|
||||
}
|
||||
// If the first object is a regular object, and it has a
|
||||
@ -418,7 +418,7 @@ void CardTableRS::verify_space(Space* s, HeapWord* gen_boundary) {
|
||||
!boundary_obj->is_typeArray()) {
|
||||
guarantee(cur_entry > byte_for(used.start()),
|
||||
"else boundary would be boundary_block");
|
||||
if (*byte_for(boundary_block) != CardTableModRefBS::clean_card) {
|
||||
if (*byte_for(boundary_block) != clean_card_val()) {
|
||||
begin = boundary_block + s->block_size(boundary_block);
|
||||
start_block = begin;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
#ifndef SHARE_VM_GC_SHARED_CARDTABLERS_HPP
|
||||
#define SHARE_VM_GC_SHARED_CARDTABLERS_HPP
|
||||
|
||||
#include "gc/shared/cardTableModRefBS.hpp"
|
||||
#include "gc/shared/cardTableModRefBSForCTRS.hpp"
|
||||
#include "gc/shared/genRemSet.hpp"
|
||||
#include "memory/memRegion.hpp"
|
||||
|
||||
@ -42,16 +42,16 @@ class CardTableRS: public GenRemSet {
|
||||
friend class ClearNoncleanCardWrapper;
|
||||
|
||||
static jbyte clean_card_val() {
|
||||
return CardTableModRefBS::clean_card;
|
||||
return CardTableModRefBSForCTRS::clean_card;
|
||||
}
|
||||
|
||||
static intptr_t clean_card_row() {
|
||||
return CardTableModRefBS::clean_card_row;
|
||||
return CardTableModRefBSForCTRS::clean_card_row;
|
||||
}
|
||||
|
||||
static bool
|
||||
card_is_dirty_wrt_gen_iter(jbyte cv) {
|
||||
return CardTableModRefBS::card_is_dirty_wrt_gen_iter(cv);
|
||||
return CardTableModRefBSForCTRS::card_is_dirty_wrt_gen_iter(cv);
|
||||
}
|
||||
|
||||
CardTableModRefBSForCTRS* _ct_bs;
|
||||
@ -61,17 +61,17 @@ class CardTableRS: public GenRemSet {
|
||||
void verify_space(Space* s, HeapWord* gen_start);
|
||||
|
||||
enum ExtendedCardValue {
|
||||
youngergen_card = CardTableModRefBS::CT_MR_BS_last_reserved + 1,
|
||||
youngergen_card = CardTableModRefBSForCTRS::CT_MR_BS_last_reserved + 1,
|
||||
// These are for parallel collection.
|
||||
// There are three P (parallel) youngergen card values. In general, this
|
||||
// needs to be more than the number of generations (including the perm
|
||||
// gen) that might have younger_refs_do invoked on them separately. So
|
||||
// if we add more gens, we have to add more values.
|
||||
youngergenP1_card = CardTableModRefBS::CT_MR_BS_last_reserved + 2,
|
||||
youngergenP2_card = CardTableModRefBS::CT_MR_BS_last_reserved + 3,
|
||||
youngergenP3_card = CardTableModRefBS::CT_MR_BS_last_reserved + 4,
|
||||
youngergenP1_card = CardTableModRefBSForCTRS::CT_MR_BS_last_reserved + 2,
|
||||
youngergenP2_card = CardTableModRefBSForCTRS::CT_MR_BS_last_reserved + 3,
|
||||
youngergenP3_card = CardTableModRefBSForCTRS::CT_MR_BS_last_reserved + 4,
|
||||
cur_youngergen_and_prev_nonclean_card =
|
||||
CardTableModRefBS::CT_MR_BS_last_reserved + 5
|
||||
CardTableModRefBSForCTRS::CT_MR_BS_last_reserved + 5
|
||||
};
|
||||
|
||||
// An array that contains, for each generation, the card table value last
|
||||
@ -107,7 +107,7 @@ public:
|
||||
// *** GenRemSet functions.
|
||||
CardTableRS* as_CardTableRS() { return this; }
|
||||
|
||||
CardTableModRefBS* ct_bs() { return _ct_bs; }
|
||||
CardTableModRefBSForCTRS* ct_bs() { return _ct_bs; }
|
||||
|
||||
// Override.
|
||||
void prepare_for_younger_refs_iterate(bool parallel);
|
||||
@ -147,7 +147,7 @@ public:
|
||||
void invalidate_or_clear(Generation* old_gen);
|
||||
|
||||
static uintx ct_max_alignment_constraint() {
|
||||
return CardTableModRefBS::ct_max_alignment_constraint();
|
||||
return CardTableModRefBSForCTRS::ct_max_alignment_constraint();
|
||||
}
|
||||
|
||||
jbyte* byte_for(void* p) { return _ct_bs->byte_for(p); }
|
||||
|
@ -200,7 +200,6 @@ class oopDesc {
|
||||
|
||||
// Access to fields in a instanceOop through these methods.
|
||||
oop obj_field(int offset) const;
|
||||
volatile oop obj_field_volatile(int offset) const;
|
||||
void obj_field_put(int offset, oop value);
|
||||
void obj_field_put_raw(int offset, oop value);
|
||||
void obj_field_put_volatile(int offset, oop value);
|
||||
|
@ -284,11 +284,7 @@ inline oop oopDesc::obj_field(int offset) const {
|
||||
load_decode_heap_oop(obj_field_addr<narrowOop>(offset)) :
|
||||
load_decode_heap_oop(obj_field_addr<oop>(offset));
|
||||
}
|
||||
inline volatile oop oopDesc::obj_field_volatile(int offset) const {
|
||||
volatile oop value = obj_field(offset);
|
||||
OrderAccess::acquire();
|
||||
return value;
|
||||
}
|
||||
|
||||
inline void oopDesc::obj_field_put(int offset, oop value) {
|
||||
UseCompressedOops ? oop_store(obj_field_addr<narrowOop>(offset), value) :
|
||||
oop_store(obj_field_addr<oop>(offset), value);
|
||||
|
@ -2824,7 +2824,7 @@ inline bool VM_HeapWalkOperation::iterate_over_class(oop java_class) {
|
||||
if (klass->oop_is_instance()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(klass);
|
||||
|
||||
// ignore the class if it's has been initialized yet
|
||||
// Ignore the class if it hasn't been initialized yet
|
||||
if (!ik->is_linked()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -788,9 +788,11 @@ void Arguments::print_on(outputStream* st) {
|
||||
st->print_cr("VM Arguments:");
|
||||
if (num_jvm_flags() > 0) {
|
||||
st->print("jvm_flags: "); print_jvm_flags_on(st);
|
||||
st->cr();
|
||||
}
|
||||
if (num_jvm_args() > 0) {
|
||||
st->print("jvm_args: "); print_jvm_args_on(st);
|
||||
st->cr();
|
||||
}
|
||||
st->print_cr("java_command: %s", java_command() ? java_command() : "<unknown>");
|
||||
if (_java_class_path != NULL) {
|
||||
@ -800,12 +802,32 @@ void Arguments::print_on(outputStream* st) {
|
||||
st->print_cr("Launcher Type: %s", _sun_java_launcher);
|
||||
}
|
||||
|
||||
void Arguments::print_summary_on(outputStream* st) {
|
||||
// Print the command line. Environment variables that are helpful for
|
||||
// reproducing the problem are written later in the hs_err file.
|
||||
// flags are from setting file
|
||||
if (num_jvm_flags() > 0) {
|
||||
st->print_raw("Settings File: ");
|
||||
print_jvm_flags_on(st);
|
||||
st->cr();
|
||||
}
|
||||
// args are the command line and environment variable arguments.
|
||||
st->print_raw("Command Line: ");
|
||||
if (num_jvm_args() > 0) {
|
||||
print_jvm_args_on(st);
|
||||
}
|
||||
// this is the classfile and any arguments to the java program
|
||||
if (java_command() != NULL) {
|
||||
st->print("%s", java_command());
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void Arguments::print_jvm_flags_on(outputStream* st) {
|
||||
if (_num_jvm_flags > 0) {
|
||||
for (int i=0; i < _num_jvm_flags; i++) {
|
||||
st->print("%s ", _jvm_flags_array[i]);
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
|
||||
@ -814,7 +836,6 @@ void Arguments::print_jvm_args_on(outputStream* st) {
|
||||
for (int i=0; i < _num_jvm_args; i++) {
|
||||
st->print("%s ", _jvm_args_array[i]);
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,6 +495,7 @@ class Arguments : AllStatic {
|
||||
|
||||
// print jvm_flags, jvm_args and java_command
|
||||
static void print_on(outputStream* st);
|
||||
static void print_summary_on(outputStream* st);
|
||||
|
||||
// convenient methods to obtain / print jvm_flags and jvm_args
|
||||
static const char* jvm_flags() { return build_resource_string(_jvm_flags_array, _num_jvm_flags); }
|
||||
|
@ -83,7 +83,6 @@ Mutex* DirtyCardQ_FL_lock = NULL;
|
||||
Monitor* DirtyCardQ_CBL_mon = NULL;
|
||||
Mutex* Shared_DirtyCardQ_lock = NULL;
|
||||
Mutex* ParGCRareEvent_lock = NULL;
|
||||
Mutex* EvacFailureStack_lock = NULL;
|
||||
Mutex* DerivedPointerTableGC_lock = NULL;
|
||||
Mutex* Compile_lock = NULL;
|
||||
Monitor* MethodCompileQueue_lock = NULL;
|
||||
@ -201,7 +200,6 @@ void mutex_init() {
|
||||
def(OldSets_lock , Mutex , leaf , true, Monitor::_safepoint_check_never);
|
||||
def(RootRegionScan_lock , Monitor, leaf , true, Monitor::_safepoint_check_never);
|
||||
def(MMUTracker_lock , Mutex , leaf , true, Monitor::_safepoint_check_never);
|
||||
def(EvacFailureStack_lock , Mutex , nonleaf , true, Monitor::_safepoint_check_never);
|
||||
|
||||
def(StringDedupQueue_lock , Monitor, leaf, true, Monitor::_safepoint_check_never);
|
||||
def(StringDedupTable_lock , Mutex , leaf, true, Monitor::_safepoint_check_never);
|
||||
|
@ -87,7 +87,6 @@ extern Mutex* Shared_DirtyCardQ_lock; // Lock protecting dirty card
|
||||
// non-Java threads.
|
||||
// (see option ExplicitGCInvokesConcurrent)
|
||||
extern Mutex* ParGCRareEvent_lock; // Synchronizes various (rare) parallel GC ops.
|
||||
extern Mutex* EvacFailureStack_lock; // guards the evac failure scan stack
|
||||
extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc)
|
||||
extern Monitor* MethodCompileQueue_lock; // a lock held when method compilations are enqueued, dequeued
|
||||
extern Monitor* CompileThread_lock; // a lock held by compile threads during compilation system initialization
|
||||
|
@ -843,6 +843,28 @@ void os::print_cpu_info(outputStream* st, char* buf, size_t buflen) {
|
||||
pd_print_cpu_info(st, buf, buflen);
|
||||
}
|
||||
|
||||
// Print a one line string summarizing the cpu, number of cores, memory, and operating system version
|
||||
void os::print_summary_info(outputStream* st, char* buf, size_t buflen) {
|
||||
st->print("Host: ");
|
||||
#ifndef PRODUCT
|
||||
if (get_host_name(buf, buflen)) {
|
||||
st->print("%s, ", buf);
|
||||
}
|
||||
#endif // PRODUCT
|
||||
get_summary_cpu_info(buf, buflen);
|
||||
st->print("%s, ", buf);
|
||||
size_t mem = physical_memory()/G;
|
||||
if (mem == 0) { // for low memory systems
|
||||
mem = physical_memory()/M;
|
||||
st->print("%d cores, %dM, ", processor_count(), mem);
|
||||
} else {
|
||||
st->print("%d cores, %dG, ", processor_count(), mem);
|
||||
}
|
||||
get_summary_os_info(buf, buflen);
|
||||
st->print_raw(buf);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
|
||||
const int secs_per_day = 86400;
|
||||
const int secs_per_hour = 3600;
|
||||
@ -850,12 +872,19 @@ void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
|
||||
|
||||
time_t tloc;
|
||||
(void)time(&tloc);
|
||||
st->print("time: %s", ctime(&tloc)); // ctime adds newline.
|
||||
char* timestring = ctime(&tloc); // ctime adds newline.
|
||||
// edit out the newline
|
||||
char* nl = strchr(timestring, '\n');
|
||||
if (nl != NULL) {
|
||||
*nl = '\0';
|
||||
}
|
||||
|
||||
struct tm tz;
|
||||
if (localtime_pd(&tloc, &tz) != NULL) {
|
||||
::strftime(buf, buflen, "%Z", &tz);
|
||||
st->print_cr("timezone: %s", buf);
|
||||
st->print("Time: %s %s", timestring, buf);
|
||||
} else {
|
||||
st->print("Time: %s", timestring);
|
||||
}
|
||||
|
||||
double t = os::elapsedTime();
|
||||
@ -872,7 +901,7 @@ void os::print_date_and_time(outputStream *st, char* buf, size_t buflen) {
|
||||
int elmins = (eltime - day_secs - hour_secs) / secs_per_min;
|
||||
int minute_secs = elmins * secs_per_min;
|
||||
int elsecs = (eltime - day_secs - hour_secs - minute_secs);
|
||||
st->print_cr("elapsed time: %d seconds (%dd %dh %dm %ds)", eltime, eldays, elhours, elmins, elsecs);
|
||||
st->print_cr(" elapsed time: %d seconds (%dd %dh %dm %ds)", eltime, eldays, elhours, elmins, elsecs);
|
||||
}
|
||||
|
||||
// moved from debug.cpp (used to be find()) but still called from there
|
||||
|
@ -150,6 +150,11 @@ class os: AllStatic {
|
||||
|
||||
static size_t page_size_for_region(size_t region_size, size_t min_pages, bool must_be_aligned);
|
||||
|
||||
// Get summary strings for system information in buffer provided
|
||||
static bool get_host_name(char* buf, size_t buflen) PRODUCT_RETURN_(return false;); // true if available
|
||||
static void get_summary_cpu_info(char* buf, size_t buflen);
|
||||
static void get_summary_os_info(char* buf, size_t buflen);
|
||||
|
||||
public:
|
||||
static void init(void); // Called before command line parsing
|
||||
static void init_before_ergo(void); // Called after command line parsing
|
||||
@ -590,6 +595,7 @@ class os: AllStatic {
|
||||
static void print_os_info_brief(outputStream* st);
|
||||
static void print_cpu_info(outputStream* st, char* buf, size_t buflen);
|
||||
static void pd_print_cpu_info(outputStream* st, char* buf, size_t buflen);
|
||||
static void print_summary_info(outputStream* st, char* buf, size_t buflen);
|
||||
static void print_memory_info(outputStream* st);
|
||||
static void print_dll_info(outputStream* st);
|
||||
static void print_environment_variables(outputStream* st, const char** env_list);
|
||||
|
@ -148,8 +148,7 @@ void javaVFrame::print_locked_object_class_name(outputStream* st, Handle obj, co
|
||||
if (obj.not_null()) {
|
||||
st->print("\t- %s <" INTPTR_FORMAT "> ", lock_state, (address)obj());
|
||||
if (obj->klass() == SystemDictionary::Class_klass()) {
|
||||
Klass* target_klass = java_lang_Class::as_Klass(obj());
|
||||
st->print_cr("(a java.lang.Class for %s)", InstanceKlass::cast(target_klass)->external_name());
|
||||
st->print_cr("(a java.lang.Class for %s)", java_lang_Class::as_external_name(obj()));
|
||||
} else {
|
||||
Klass* k = obj->klass();
|
||||
st->print_cr("(a %s)", k->external_name());
|
||||
|
@ -899,6 +899,11 @@ void DumperSupport::dump_class_and_array_classes(DumpWriter* writer, Klass* k) {
|
||||
assert(klass->oop_is_instance(), "not an InstanceKlass");
|
||||
InstanceKlass* ik = (InstanceKlass*)klass;
|
||||
|
||||
// Ignore the class if it hasn't been initialized yet
|
||||
if (!ik->is_linked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
writer->write_u1(HPROF_GC_CLASS_DUMP);
|
||||
|
||||
// class ID
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "ci/ciMethod.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/cardTableModRefBS.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
@ -442,7 +444,7 @@ void SharkBuilder::CreateUpdateBarrierSet(BarrierSet* bs, Value* field) {
|
||||
Unimplemented();
|
||||
|
||||
CreateStore(
|
||||
LLVMValue::jbyte_constant(CardTableModRefBS::dirty_card),
|
||||
LLVMValue::jbyte_constant(CardTableModRefBS::dirty_card_val()),
|
||||
CreateIntToPtr(
|
||||
CreateAdd(
|
||||
LLVMValue::intptr_constant(
|
||||
|
@ -27,8 +27,6 @@
|
||||
#define SHARE_VM_SHARK_SHARKBUILDER_HPP
|
||||
|
||||
#include "ci/ciType.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/cardTableModRefBS.hpp"
|
||||
#include "shark/llvmHeaders.hpp"
|
||||
#include "shark/llvmValue.hpp"
|
||||
#include "shark/sharkCodeBuffer.hpp"
|
||||
@ -38,6 +36,8 @@
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/sizes.hpp"
|
||||
|
||||
class BarrierSet;
|
||||
|
||||
class SharkBuilder : public llvm::IRBuilder<> {
|
||||
friend class SharkCompileInvariants;
|
||||
|
||||
|
@ -306,6 +306,30 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt,
|
||||
#endif // ZERO
|
||||
}
|
||||
|
||||
void VMError::print_oom_reasons(outputStream* st) {
|
||||
st->print_cr("# Possible reasons:");
|
||||
st->print_cr("# The system is out of physical RAM or swap space");
|
||||
st->print_cr("# In 32 bit mode, the process size limit was hit");
|
||||
st->print_cr("# Possible solutions:");
|
||||
st->print_cr("# Reduce memory load on the system");
|
||||
st->print_cr("# Increase physical memory or swap space");
|
||||
st->print_cr("# Check if swap backing store is full");
|
||||
st->print_cr("# Use 64 bit Java on a 64 bit OS");
|
||||
st->print_cr("# Decrease Java heap size (-Xmx/-Xms)");
|
||||
st->print_cr("# Decrease number of Java threads");
|
||||
st->print_cr("# Decrease Java thread stack sizes (-Xss)");
|
||||
st->print_cr("# Set larger code cache with -XX:ReservedCodeCacheSize=");
|
||||
st->print_cr("# This output file may be truncated or incomplete.");
|
||||
}
|
||||
|
||||
const char* VMError::gc_mode() {
|
||||
if (UseG1GC) return "g1 gc";
|
||||
if (UseParallelGC) return "parallel gc";
|
||||
if (UseConcMarkSweepGC) return "concurrent mark sweep gc";
|
||||
if (UseSerialGC) return "serial gc";
|
||||
return "ERROR in GC mode";
|
||||
}
|
||||
|
||||
// This is the main function to report a fatal error. Only one thread can
|
||||
// call this function, so we don't need to worry about MT-safety. But it's
|
||||
// possible that the error handler itself may crash or die on an internal
|
||||
@ -358,21 +382,21 @@ void VMError::report(outputStream* st) {
|
||||
|
||||
// test secondary error handling. Test it twice, to test that resetting
|
||||
// error handler after a secondary crash works.
|
||||
STEP(11, "(test secondary crash 1)")
|
||||
STEP(20, "(test secondary crash 1)")
|
||||
if (_verbose && TestCrashInErrorHandler != 0) {
|
||||
st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...",
|
||||
TestCrashInErrorHandler);
|
||||
controlled_crash(TestCrashInErrorHandler);
|
||||
}
|
||||
|
||||
STEP(12, "(test secondary crash 2)")
|
||||
STEP(30, "(test secondary crash 2)")
|
||||
if (_verbose && TestCrashInErrorHandler != 0) {
|
||||
st->print_cr("Will crash now (TestCrashInErrorHandler=%d)...",
|
||||
TestCrashInErrorHandler);
|
||||
controlled_crash(TestCrashInErrorHandler);
|
||||
}
|
||||
|
||||
STEP(13, "(test safefetch in error handler)")
|
||||
STEP(40, "(test safefetch in error handler)")
|
||||
// test whether it is safe to use SafeFetch32 in Crash Handler. Test twice
|
||||
// to test that resetting the signal handler works correctly.
|
||||
if (_verbose && TestSafeFetchInErrorHandler) {
|
||||
@ -393,7 +417,7 @@ void VMError::report(outputStream* st) {
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
STEP(15, "(printing type of error)")
|
||||
STEP(50, "(printing type of error)")
|
||||
|
||||
switch(_id) {
|
||||
case OOM_MALLOC_ERROR:
|
||||
@ -418,19 +442,7 @@ void VMError::report(outputStream* st) {
|
||||
}
|
||||
// In error file give some solutions
|
||||
if (_verbose) {
|
||||
st->print_cr("# Possible reasons:");
|
||||
st->print_cr("# The system is out of physical RAM or swap space");
|
||||
st->print_cr("# In 32 bit mode, the process size limit was hit");
|
||||
st->print_cr("# Possible solutions:");
|
||||
st->print_cr("# Reduce memory load on the system");
|
||||
st->print_cr("# Increase physical memory or swap space");
|
||||
st->print_cr("# Check if swap backing store is full");
|
||||
st->print_cr("# Use 64 bit Java on a 64 bit OS");
|
||||
st->print_cr("# Decrease Java heap size (-Xmx/-Xms)");
|
||||
st->print_cr("# Decrease number of Java threads");
|
||||
st->print_cr("# Decrease Java thread stack sizes (-Xss)");
|
||||
st->print_cr("# Set larger code cache with -XX:ReservedCodeCacheSize=");
|
||||
st->print_cr("# This output file may be truncated or incomplete.");
|
||||
print_oom_reasons(st);
|
||||
} else {
|
||||
return; // that's enough for the screen
|
||||
}
|
||||
@ -440,7 +452,7 @@ void VMError::report(outputStream* st) {
|
||||
break;
|
||||
}
|
||||
|
||||
STEP(20, "(printing exception/signal name)")
|
||||
STEP(60, "(printing exception/signal name)")
|
||||
|
||||
st->print_cr("#");
|
||||
st->print("# ");
|
||||
@ -470,14 +482,14 @@ void VMError::report(outputStream* st) {
|
||||
}
|
||||
}
|
||||
|
||||
STEP(30, "(printing current thread and pid)")
|
||||
STEP(70, "(printing current thread and pid)")
|
||||
|
||||
// process id, thread id
|
||||
st->print(", pid=%d", os::current_process_id());
|
||||
st->print(", tid=" INTPTR_FORMAT, os::current_thread_id());
|
||||
st->cr();
|
||||
|
||||
STEP(40, "(printing error message)")
|
||||
STEP(80, "(printing error message)")
|
||||
|
||||
if (should_report_bug(_id)) { // already printed the message.
|
||||
// error message
|
||||
@ -488,7 +500,7 @@ void VMError::report(outputStream* st) {
|
||||
}
|
||||
}
|
||||
|
||||
STEP(50, "(printing Java version string)")
|
||||
STEP(90, "(printing Java version string)")
|
||||
|
||||
// VM version
|
||||
st->print_cr("#");
|
||||
@ -498,15 +510,18 @@ void VMError::report(outputStream* st) {
|
||||
const char* runtime_version = JDK_Version::runtime_version() != NULL ?
|
||||
JDK_Version::runtime_version() : "";
|
||||
st->print_cr("# JRE version: %s (%s) (build %s)", runtime_name, buf, runtime_version);
|
||||
st->print_cr("# Java VM: %s (%s %s %s %s)",
|
||||
// This is the long version with some default settings added
|
||||
st->print_cr("# Java VM: %s (%s, %s%s%s, %s, %s)",
|
||||
Abstract_VM_Version::vm_name(),
|
||||
Abstract_VM_Version::vm_release(),
|
||||
Abstract_VM_Version::vm_info_string(),
|
||||
Abstract_VM_Version::vm_platform_string(),
|
||||
UseCompressedOops ? "compressed oops" : ""
|
||||
TieredCompilation ? ", tiered" : "",
|
||||
UseCompressedOops ? ", compressed oops" : "",
|
||||
gc_mode(),
|
||||
Abstract_VM_Version::vm_platform_string()
|
||||
);
|
||||
|
||||
STEP(60, "(printing problematic frame)")
|
||||
STEP(100, "(printing problematic frame)")
|
||||
|
||||
// Print current frame if we have a context (i.e. it's a crash)
|
||||
if (_context) {
|
||||
@ -517,7 +532,8 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
st->print_cr("#");
|
||||
}
|
||||
STEP(63, "(printing core file information)")
|
||||
|
||||
STEP(110, "(printing core file information)")
|
||||
st->print("# ");
|
||||
if (CreateCoredumpOnCrash) {
|
||||
if (coredump_status) {
|
||||
@ -531,13 +547,42 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
st->print_cr("#");
|
||||
|
||||
STEP(65, "(printing bug submit message)")
|
||||
STEP(120, "(printing bug submit message)")
|
||||
|
||||
if (should_report_bug(_id) && _verbose) {
|
||||
print_bug_submit_message(st, _thread);
|
||||
}
|
||||
|
||||
STEP(70, "(printing thread)" )
|
||||
STEP(130, "(printing summary)" )
|
||||
|
||||
if (_verbose) {
|
||||
st->cr();
|
||||
st->print_cr("--------------- S U M M A R Y ------------");
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(140, "(printing VM option summary)" )
|
||||
|
||||
if (_verbose) {
|
||||
// VM options
|
||||
Arguments::print_summary_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(150, "(printing summary machine and OS info)")
|
||||
|
||||
if (_verbose) {
|
||||
os::print_summary_info(st, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
|
||||
STEP(160, "(printing date and time)" )
|
||||
|
||||
if (_verbose) {
|
||||
os::print_date_and_time(st, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
STEP(170, "(printing thread)" )
|
||||
|
||||
if (_verbose) {
|
||||
st->cr();
|
||||
@ -545,7 +590,7 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(80, "(printing current thread)" )
|
||||
STEP(180, "(printing current thread)" )
|
||||
|
||||
// current thread
|
||||
if (_verbose) {
|
||||
@ -559,31 +604,20 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(90, "(printing siginfo)" )
|
||||
STEP(190, "(printing current compile task)" )
|
||||
|
||||
// signal no, signal code, address that caused the fault
|
||||
if (_verbose && _siginfo) {
|
||||
os::print_siginfo(st, _siginfo);
|
||||
st->cr();
|
||||
if (_verbose && _thread && _thread->is_Compiler_thread()) {
|
||||
CompilerThread* t = (CompilerThread*)_thread;
|
||||
if (t->task()) {
|
||||
st->cr();
|
||||
st->print_cr("Current CompileTask:");
|
||||
t->task()->print_line_on_error(st, buf, sizeof(buf));
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
|
||||
STEP(100, "(printing registers, top of stack, instructions near pc)")
|
||||
|
||||
// registers, top of stack, instructions near pc
|
||||
if (_verbose && _context) {
|
||||
os::print_context(st, _context);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(105, "(printing register info)")
|
||||
|
||||
// decode register contents if possible
|
||||
if (_verbose && _context && Universe::is_fully_initialized()) {
|
||||
os::print_register_info(st, _context);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(110, "(printing stack bounds)" )
|
||||
STEP(200, "(printing stack bounds)" )
|
||||
|
||||
if (_verbose) {
|
||||
st->print("Stack: ");
|
||||
@ -614,7 +648,7 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(120, "(printing native stack)" )
|
||||
STEP(210, "(printing native stack)" )
|
||||
|
||||
if (_verbose) {
|
||||
if (os::platform_print_native_stack(st, _context, buf, sizeof(buf))) {
|
||||
@ -628,13 +662,13 @@ void VMError::report(outputStream* st) {
|
||||
}
|
||||
}
|
||||
|
||||
STEP(130, "(printing Java stack)" )
|
||||
STEP(220, "(printing Java stack)" )
|
||||
|
||||
if (_verbose && _thread && _thread->is_Java_thread()) {
|
||||
print_stack_trace(st, (JavaThread*)_thread, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
STEP(135, "(printing target Java thread stack)" )
|
||||
STEP(230, "(printing target Java thread stack)" )
|
||||
|
||||
// printing Java thread stack trace if it is involved in GC crash
|
||||
if (_verbose && _thread && (_thread->is_Named_thread())) {
|
||||
@ -645,7 +679,32 @@ void VMError::report(outputStream* st) {
|
||||
}
|
||||
}
|
||||
|
||||
STEP(140, "(printing VM operation)" )
|
||||
STEP(240, "(printing siginfo)" )
|
||||
|
||||
// signal no, signal code, address that caused the fault
|
||||
if (_verbose && _siginfo) {
|
||||
st->cr();
|
||||
os::print_siginfo(st, _siginfo);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(250, "(printing register info)")
|
||||
|
||||
// decode register contents if possible
|
||||
if (_verbose && _context && Universe::is_fully_initialized()) {
|
||||
os::print_register_info(st, _context);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(260, "(printing registers, top of stack, instructions near pc)")
|
||||
|
||||
// registers, top of stack, instructions near pc
|
||||
if (_verbose && _context) {
|
||||
os::print_context(st, _context);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(270, "(printing VM operation)" )
|
||||
|
||||
if (_verbose && _thread && _thread->is_VM_thread()) {
|
||||
VMThread* t = (VMThread*)_thread;
|
||||
@ -657,19 +716,7 @@ void VMError::report(outputStream* st) {
|
||||
}
|
||||
}
|
||||
|
||||
STEP(150, "(printing current compile task)" )
|
||||
|
||||
if (_verbose && _thread && _thread->is_Compiler_thread()) {
|
||||
CompilerThread* t = (CompilerThread*)_thread;
|
||||
if (t->task()) {
|
||||
st->cr();
|
||||
st->print_cr("Current CompileTask:");
|
||||
t->task()->print_line_on_error(st, buf, sizeof(buf));
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
|
||||
STEP(160, "(printing process)" )
|
||||
STEP(280, "(printing process)" )
|
||||
|
||||
if (_verbose) {
|
||||
st->cr();
|
||||
@ -677,7 +724,7 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(170, "(printing all threads)" )
|
||||
STEP(290, "(printing all threads)" )
|
||||
|
||||
// all threads
|
||||
if (_verbose && _thread) {
|
||||
@ -685,7 +732,7 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(175, "(printing VM state)" )
|
||||
STEP(300, "(printing VM state)" )
|
||||
|
||||
if (_verbose) {
|
||||
// Safepoint state
|
||||
@ -707,7 +754,7 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(180, "(printing owned locks on error)" )
|
||||
STEP(310, "(printing owned locks on error)" )
|
||||
|
||||
// mutexes/monitors that currently have an owner
|
||||
if (_verbose) {
|
||||
@ -715,7 +762,7 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(182, "(printing number of OutOfMemoryError and StackOverflow exceptions)")
|
||||
STEP(320, "(printing number of OutOfMemoryError and StackOverflow exceptions)")
|
||||
|
||||
if (_verbose && Exceptions::has_exception_counts()) {
|
||||
st->print_cr("OutOfMemory and StackOverflow Exception counts:");
|
||||
@ -723,7 +770,7 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(185, "(printing compressed oops mode")
|
||||
STEP(330, "(printing compressed oops mode")
|
||||
|
||||
if (_verbose && UseCompressedOops) {
|
||||
Universe::print_compressed_oops_mode(st);
|
||||
@ -733,7 +780,7 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(190, "(printing heap information)" )
|
||||
STEP(340, "(printing heap information)" )
|
||||
|
||||
if (_verbose && Universe::is_fully_initialized()) {
|
||||
Universe::heap()->print_on_error(st);
|
||||
@ -743,7 +790,7 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(195, "(printing code cache information)" )
|
||||
STEP(350, "(printing code cache information)" )
|
||||
|
||||
if (_verbose && Universe::is_fully_initialized()) {
|
||||
// print code cache information before vm abort
|
||||
@ -751,14 +798,14 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(200, "(printing ring buffers)" )
|
||||
STEP(360, "(printing ring buffers)" )
|
||||
|
||||
if (_verbose) {
|
||||
Events::print_all(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(205, "(printing dynamic libraries)" )
|
||||
STEP(370, "(printing dynamic libraries)" )
|
||||
|
||||
if (_verbose) {
|
||||
// dynamic libraries, or memory map
|
||||
@ -766,7 +813,7 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(210, "(printing VM options)" )
|
||||
STEP(380, "(printing VM options)" )
|
||||
|
||||
if (_verbose) {
|
||||
// VM options
|
||||
@ -774,33 +821,33 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(215, "(printing warning if internal testing API used)" )
|
||||
STEP(390, "(printing warning if internal testing API used)" )
|
||||
|
||||
if (WhiteBox::used()) {
|
||||
st->print_cr("Unsupported internal testing APIs have been used.");
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(220, "(printing environment variables)" )
|
||||
STEP(400, "(printing all environment variables)" )
|
||||
|
||||
if (_verbose) {
|
||||
os::print_environment_variables(st, env_list);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(225, "(printing signal handlers)" )
|
||||
STEP(410, "(printing signal handlers)" )
|
||||
|
||||
if (_verbose) {
|
||||
os::print_signal_handlers(st, buf, sizeof(buf));
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(228, "(Native Memory Tracking)" )
|
||||
STEP(420, "(Native Memory Tracking)" )
|
||||
if (_verbose) {
|
||||
MemTracker::error_report(st);
|
||||
}
|
||||
|
||||
STEP(230, "" )
|
||||
STEP(430, "(printing system)" )
|
||||
|
||||
if (_verbose) {
|
||||
st->cr();
|
||||
@ -808,48 +855,39 @@ void VMError::report(outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(240, "(printing OS information)" )
|
||||
STEP(440, "(printing OS information)" )
|
||||
|
||||
if (_verbose) {
|
||||
os::print_os_info(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(250, "(printing CPU info)" )
|
||||
STEP(450, "(printing CPU info)" )
|
||||
if (_verbose) {
|
||||
os::print_cpu_info(st, buf, sizeof(buf));
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(260, "(printing memory info)" )
|
||||
STEP(460, "(printing memory info)" )
|
||||
|
||||
if (_verbose) {
|
||||
os::print_memory_info(st);
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(270, "(printing internal vm info)" )
|
||||
STEP(470, "(printing internal vm info)" )
|
||||
|
||||
if (_verbose) {
|
||||
st->print_cr("vm_info: %s", Abstract_VM_Version::internal_vm_info_string());
|
||||
st->cr();
|
||||
}
|
||||
|
||||
STEP(280, "(printing date and time)" )
|
||||
|
||||
if (_verbose) {
|
||||
os::print_date_and_time(st, buf, sizeof(buf));
|
||||
st->cr();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// print a defined marker to show that error handling finished correctly.
|
||||
STEP(290, "(printing end marker)" )
|
||||
STEP(480, "(printing end marker)" )
|
||||
|
||||
if (_verbose) {
|
||||
st->print_cr("END.");
|
||||
}
|
||||
#endif
|
||||
|
||||
END
|
||||
|
||||
|
@ -89,6 +89,9 @@ class VMError : public StackObj {
|
||||
static void print_stack_trace(outputStream* st, JavaThread* jt,
|
||||
char* buf, int buflen, bool verbose = false);
|
||||
|
||||
static const char* gc_mode();
|
||||
static void print_oom_reasons(outputStream* st);
|
||||
|
||||
// accessor
|
||||
const char* message() const { return _message; }
|
||||
const char* detail_msg() const { return _detail_msg; }
|
||||
|
@ -94,29 +94,47 @@ public class TestLargePageUseForAuxMemory {
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
private static long gcd(long x, long y) {
|
||||
while (x > 0) {
|
||||
long t = x;
|
||||
x = y % x;
|
||||
y = t;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
private static long lcm(long x, long y) {
|
||||
return x * (y / gcd(x, y));
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (!Platform.isDebugBuild()) {
|
||||
System.out.println("Skip tests on non-debug builds because the required option TracePageSizes is a debug-only option.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Size that a single card covers.
|
||||
final int cardSize = 512;
|
||||
WhiteBox wb = WhiteBox.getWhiteBox();
|
||||
smallPageSize = wb.getVMPageSize();
|
||||
largePageSize = wb.getVMLargePageSize();
|
||||
allocGranularity = wb.getVMAllocationGranularity();
|
||||
final long heapAlignment = lcm(cardSize * smallPageSize, largePageSize);
|
||||
|
||||
if (largePageSize == 0) {
|
||||
System.out.println("Skip tests because large page support does not seem to be available on this platform.");
|
||||
return;
|
||||
}
|
||||
if (largePageSize == smallPageSize) {
|
||||
System.out.println("Skip tests because large page support does not seem to be available on this platform." +
|
||||
"Small and large page size are the same.");
|
||||
return;
|
||||
}
|
||||
|
||||
// To get large pages for the card table etc. we need at least a 1G heap (with 4k page size).
|
||||
// 32 bit systems will have problems reserving such an amount of contiguous space, so skip the
|
||||
// test there.
|
||||
if (!Platform.is32bit()) {
|
||||
// Size that a single card covers.
|
||||
final int cardSize = 512;
|
||||
|
||||
final long heapSizeForCardTableUsingLargePages = largePageSize * cardSize;
|
||||
final long heapSizeDiffForCardTable = Math.max(Math.max(allocGranularity * cardSize, HEAP_REGION_SIZE), largePageSize);
|
||||
|
||||
@ -131,7 +149,8 @@ public class TestLargePageUseForAuxMemory {
|
||||
// everywhere.
|
||||
final int bitmapTranslationFactor = 8 * 8; // ObjectAlignmentInBytes * BitsPerByte
|
||||
final long heapSizeForBitmapUsingLargePages = largePageSize * bitmapTranslationFactor;
|
||||
final long heapSizeDiffForBitmap = Math.max(Math.max(allocGranularity * bitmapTranslationFactor, HEAP_REGION_SIZE), largePageSize);
|
||||
final long heapSizeDiffForBitmap = Math.max(Math.max(allocGranularity * bitmapTranslationFactor, HEAP_REGION_SIZE),
|
||||
Math.max(largePageSize, heapAlignment));
|
||||
|
||||
Asserts.assertGT(heapSizeForBitmapUsingLargePages, heapSizeDiffForBitmap,
|
||||
"To test we would require to use an invalid heap size");
|
||||
|
@ -38,7 +38,7 @@ import sun.misc.Unsafe;
|
||||
public class CreateCoredumpOnCrash {
|
||||
private static class Crasher {
|
||||
public static void main(String[] args) {
|
||||
Utils.getUnsafe().getInt(0);
|
||||
Utils.getUnsafe().putInt(0L, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
55
hotspot/test/runtime/verifier/PrimIntArray.java
Normal file
55
hotspot/test/runtime/verifier/PrimIntArray.java
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 8129895
|
||||
* @summary Throw VerifyError when checking assignability of primitive arrays
|
||||
* that are not identical. For example, [I is not assignable to [B.
|
||||
* @compile primArray.jasm
|
||||
* @compile primArray49.jasm
|
||||
* @run main/othervm -Xverify:all PrimIntArray
|
||||
*/
|
||||
|
||||
// Test that an int[] is not assignable to byte[].
|
||||
public class PrimIntArray {
|
||||
|
||||
public static void main(String args[]) throws Throwable {
|
||||
System.out.println("Regression test for bug 8129895");
|
||||
|
||||
try {
|
||||
Class newClass = Class.forName("primArray");
|
||||
throw new RuntimeException("Expected VerifyError exception not thrown with new verifier");
|
||||
} catch (java.lang.VerifyError e) {
|
||||
System.out.println("Test PrimIntArray passed with new verifier");
|
||||
}
|
||||
|
||||
try {
|
||||
Class newClass = Class.forName("primArray49");
|
||||
throw new RuntimeException("Expected VerifyError exception not thrown by old verifier");
|
||||
} catch (java.lang.VerifyError e) {
|
||||
System.out.println("Test PrimIntArray passed with old verifier");
|
||||
}
|
||||
}
|
||||
}
|
46
hotspot/test/runtime/verifier/primArray.jasm
Normal file
46
hotspot/test/runtime/verifier/primArray.jasm
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
// Method castToByteArray() tries to return an array of ints when an array
|
||||
// of bytes is expected.
|
||||
super class primArray
|
||||
version 52:0
|
||||
{
|
||||
|
||||
public Method "<init>":"()V"
|
||||
stack 1 locals 1
|
||||
{
|
||||
aload_0;
|
||||
invokespecial Method java/lang/Object."<init>":"()V";
|
||||
return;
|
||||
}
|
||||
|
||||
public static Method castToByteArray:"([I)[B"
|
||||
stack 1 locals 1
|
||||
{
|
||||
aload_0;
|
||||
areturn;
|
||||
}
|
||||
|
||||
} // end Class primArray
|
46
hotspot/test/runtime/verifier/primArray49.jasm
Normal file
46
hotspot/test/runtime/verifier/primArray49.jasm
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
// Method castToByteArray() tries to return an array of ints when an array
|
||||
// of bytes is expected.
|
||||
super class primArray49
|
||||
version 49:0
|
||||
{
|
||||
|
||||
public Method "<init>":"()V"
|
||||
stack 1 locals 1
|
||||
{
|
||||
aload_0;
|
||||
invokespecial Method java/lang/Object."<init>":"()V";
|
||||
return;
|
||||
}
|
||||
|
||||
public static Method castToByteArray:"([I)[B"
|
||||
stack 1 locals 1
|
||||
{
|
||||
aload_0;
|
||||
areturn;
|
||||
}
|
||||
|
||||
} // end Class primArray49
|
@ -34,7 +34,6 @@ import jdk.test.lib.apps.LingeredApp;
|
||||
* @test
|
||||
* @library /../../test/lib/share/classes
|
||||
* @library /testlibrary
|
||||
* @ignore 8129971
|
||||
* @build jdk.test.lib.*
|
||||
* @build jdk.test.lib.apps.*
|
||||
* @run main TestStackTrace
|
||||
|
Loading…
x
Reference in New Issue
Block a user