This commit is contained in:
Lana Steuck 2013-09-06 14:15:02 -07:00
commit e585259ea2
1253 changed files with 51101 additions and 18956 deletions

View File

@ -225,3 +225,5 @@ ea73f01b9053e7165e7ba80f242bafecbc6af712 jdk8-b96
edb01c460d4cab21ff0ff13512df7b746efaa0e7 jdk8-b101
bbe43d712fe08e650808d774861b256ccb34e500 jdk8-b102
30a1d677a20c6a95f98043d8f20ce570304e3818 jdk8-b103
b5ed503c26ad38869c247c5e32debec217fd056b jdk8-b104
589f4fdc584e373a47cde0162e9eceec9165c381 jdk8-b105

View File

@ -226,3 +226,5 @@ d2dcb110e9dbaf9903c05b211df800e78e4b394e jdk8-b100
5eb3c1dc348f72a7f84f7d9d07834e8bbe09a799 jdk8-b102
b7e64be81c8a7690703df5711f4fc2375da8a9cb jdk8-b103
96c1b9b7524b52c3fcefc90ffad4c767396727c8 jdk8-b104
5166118c59178b5d31001bc4058e92486ee07d9b jdk8-b105
8e7b4d9fb00fdf1334376aeac050c9bca6d1b383 jdk8-b106

View File

@ -69,11 +69,11 @@ else
# Run the makefile with an arbitraty SPEC using -p -q (quiet dry-run and dump rules) to find
# available PHONY targets. Use this list as valid targets to pass on to the repeated calls.
all_phony_targets=$(filter-out $(global_targets) bundles-only, $(strip $(shell \
$(MAKE) -p -q -f common/makefiles/Main.gmk SPEC=$(firstword $(SPEC)) | \
$(MAKE) -p -q -f common/makefiles/Main.gmk FRC SPEC=$(firstword $(SPEC)) | \
grep ^.PHONY: | head -n 1 | cut -d " " -f 2-)))
$(all_phony_targets):
$(foreach spec,$(SPEC),($(MAKE) -f NewMakefile.gmk SPEC=$(spec) \
@$(foreach spec,$(SPEC),($(MAKE) -f NewMakefile.gmk SPEC=$(spec) \
$(VERBOSE) VERBOSE=$(VERBOSE) LOG_LEVEL=$(LOG_LEVEL) $@) &&) true
.PHONY: $(all_phony_targets)

View File

@ -154,7 +154,7 @@
</code>
</blockquote>
Once you have all the repositories, keep in mind that each
repository is it's own independent repository.
repository is its own independent repository.
You can also re-run <code>./get_source.sh</code> anytime to
pull over all the latest changesets in all the repositories.
This set of nested repositories has been given the term
@ -241,6 +241,14 @@
source code for the OpenJDK Corba functionality
</td>
</tr>
<tr>
<td>
nashorn
</td>
<td>
source code for the OpenJDK JavaScript implementation
</td>
</tr>
</tbody>
</table>
</blockquote>
@ -386,7 +394,7 @@
<code>--with-boot-jdk</code>.
</li>
<li>
Insure that GNU make, the Bootstrap JDK,
Ensure that GNU make, the Bootstrap JDK,
and the compilers are all
in your PATH environment variable
</li>
@ -1202,19 +1210,18 @@
<blockquote>
<p>
<b>Q:</b> The <code>configure</code> file looks horrible!
<b>Q:</b> The <code>generated-configure.sh</code> file looks horrible!
How are you going to edit it?
<br>
<b>A:</b> The <code>configure</code> file is generated (think
<b>A:</b> The <code>generated-configure.sh</code> file is generated (think
"compiled") by the autoconf tools. The source code is
in <code>configure.ac</code> various .m4 files in common/autoconf,
which are
much more readable.
in <code>configure.ac</code> and various .m4 files in common/autoconf,
which are much more readable.
</p>
<p>
<b>Q:</b>
Why is the <code>configure</code> file checked in,
Why is the <code>generated-configure.sh</code> file checked in,
if it is generated?
<br>
<b>A:</b>
@ -1229,13 +1236,29 @@
<p>
<b>Q:</b>
Do you require a specific version of autoconf for regenerating
<code>configure</code>?
<code>generated-configure.sh</code>?
<br>
<b>A:</b>
Currently, no, but this will likely be the case when things have
settled down a bit more. (The reason for this is to avoid
large spurious changes in <code>configure</code>
in commits that made small changes to <code>configure.ac</code>).
Yes, version 2.69 is required and should be easy
enough to aquire on all supported operating
systems. The reason for this is to avoid
large spurious changes in <code>generated-configure.sh</code>.
</p>
<p>
<b>Q:</b>
How do you regenerate <code>generated-configure.sh</code>
after making changes to the input files?
<br>
<b>A:</b>
Regnerating <code>generated-configure.sh</code>
should always be done using the
script <code>common/autoconf/autogen.sh</code> to
ensure that the correct files get updated. This
script should also be run after mercurial tries to
merge <code>generated-configure.sh</code> as a
merge of the generated file is not guaranteed to
be correct.
</p>
<p>
@ -1307,9 +1330,9 @@
you will need to modify the makefiles. But for normal file
additions or removals, no changes are needed. There are certan
exceptions for some native libraries where the source files are spread
over many directories which also contain courses for other
over many directories which also contain sources for other
libraries. In these cases it was simply easier to create include lists
rather thane excludes.
rather than excludes.
</p>
<p>
@ -1327,14 +1350,14 @@
<p>
<b>Q:</b>
<code>configure</code> provides OpenJDK-specific features such as
<code>--enable-jigsaw</code> or <code>--with-builddeps-server</code>
that are not described in this document. What about those?
<code>--with-builddeps-server</code> that are not
described in this document. What about those?
<br>
<b>A:</b>
Try them out if you like! But be aware that most of these are
experimental features.
Many of them don't do anything at all at the moment; the option
is just a placeholder. Other depends on
is just a placeholder. Others depend on
pieces of code or infrastructure that is currently
not ready for prime time.
</p>
@ -1385,24 +1408,6 @@
system and some will need to wait until after.
</p>
<p>
<b>Q:</b> What is @GenerateNativeHeaders?
<br>
<b>A:</b>
To speed up compilation, we added a flag to javac which makes it
do the job of javah as well, as a by-product; that is, generating
native .h header files. These files are only generated
if a class contains native methods. However, sometimes
a class contains no native method,
but still contains constants that native code needs to use.
The new GenerateNativeHeaders annotation tells javac to
force generation of a
header file in these cases. (We don't want to generate
native headers for all classes that contains constants
but no native methods, since
that would slow down the compilation process needlessly.)
</p>
<p>
<b>Q:</b>
Is anything able to use the results of the new build's default make target?
@ -1429,10 +1434,9 @@
What should I do?
<br>
<b>A:</b>
It might very well be that we have missed to add support for
It might very well be that we have neglected to add support for
an option that was actually used from outside the build system.
Email us and we will
add support for it!
Email us and we will add support for it!
</p>
</blockquote>

View File

@ -44,10 +44,8 @@ fi
custom_hook=$custom_script_dir/custom-hook.m4
AUTOCONF="`which autoconf 2> /dev/null | grep -v '^no autoconf in'`"
AUTOCONF_267="`which autoconf-2.67 2> /dev/null | grep -v '^no autoconf-2.67 in'`"
echo "Autoconf found: ${AUTOCONF}"
echo "Autoconf-2.67 found: ${AUTOCONF_267}"
if test "x${AUTOCONF}" = x; then
echo You need autoconf installed to be able to regenerate the configure script
@ -55,10 +53,6 @@ if test "x${AUTOCONF}" = x; then
exit 1
fi
if test "x${AUTOCONF_267}" != x; then
AUTOCONF=${AUTOCONF_267};
fi
echo Generating generated-configure.sh with ${AUTOCONF}
cat $script_dir/configure.ac | sed -e "s|@DATE_WHEN_GENERATED@|$TIMESTAMP|" | ${AUTOCONF} -W all -I$script_dir - > $script_dir/generated-configure.sh
rm -rf autom4te.cache

View File

@ -30,7 +30,7 @@
###############################################################################
AC_PREREQ([2.61])
AC_PREREQ([2.69])
AC_INIT(OpenJDK, jdk8, build-dev@openjdk.java.net,,http://openjdk.java.net)
AC_CONFIG_AUX_DIR([build-aux])

File diff suppressed because it is too large Load Diff

View File

@ -83,7 +83,7 @@ apt_help() {
pulse)
PKGHANDLER_COMMAND="sudo apt-get install libpulse-dev" ;;
x11)
PKGHANDLER_COMMAND="sudo apt-get install libX11-dev libxext-dev libxrender-dev libxtst-dev" ;;
PKGHANDLER_COMMAND="sudo apt-get install libX11-dev libxext-dev libxrender-dev libxtst-dev libxt-dev" ;;
ccache)
PKGHANDLER_COMMAND="sudo apt-get install ccache" ;;
* )
@ -102,11 +102,11 @@ yum_help() {
cups)
PKGHANDLER_COMMAND="sudo yum install cups-devel" ;;
freetype2)
PKGHANDLER_COMMAND="sudo yum install freetype2-devel" ;;
PKGHANDLER_COMMAND="sudo yum install freetype-devel" ;;
pulse)
PKGHANDLER_COMMAND="sudo yum install pulseaudio-libs-devel" ;;
x11)
PKGHANDLER_COMMAND="sudo yum install libXtst-devel" ;;
PKGHANDLER_COMMAND="sudo yum install libXtst-devel libXt-devel libXrender-devel" ;;
ccache)
PKGHANDLER_COMMAND="sudo yum install ccache" ;;
* )

View File

@ -185,7 +185,7 @@ OLD_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $X_CFLAGS"
# Need to include Xlib.h and Xutil.h to avoid "present but cannot be compiled" warnings on Solaris 10
AC_CHECK_HEADERS([X11/extensions/shape.h X11/extensions/Xrender.h X11/extensions/XTest.h],
AC_CHECK_HEADERS([X11/extensions/shape.h X11/extensions/Xrender.h X11/extensions/XTest.h X11/Intrinsic.h],
[X11_A_OK=yes],
[X11_A_OK=no; break],
[ # include <X11/Xlib.h>
@ -197,7 +197,7 @@ AC_LANG_POP(C)
if test "x$X11_A_OK" = xno && test "x$X11_NOT_NEEDED" != xyes; then
HELP_MSG_MISSING_DEPENDENCY([x11])
AC_MSG_ERROR([Could not find all X11 headers (shape.h Xrender.h XTest.h). $HELP_MSG])
AC_MSG_ERROR([Could not find all X11 headers (shape.h Xrender.h XTest.h Intrinsic.h). $HELP_MSG])
fi
AC_SUBST(X_CFLAGS)

View File

@ -242,7 +242,7 @@ clean-test:
.PHONY: langtools corba jaxp jaxws hotspot jdk nashorn images overlay-images install test docs
.PHONY: langtools-only corba-only jaxp-only jaxws-only hotspot-only jdk-only nashorn-only images-only overlay-images-only install-only test-only docs-only
.PHONY: all clean dist-clean bootcycle-images start-make
.PHONY: default all clean dist-clean bootcycle-images start-make
.PHONY: clean-langtools clean-corba clean-jaxp clean-jaxws clean-hotspot clean-jdk clean-nashorn clean-images clean-docs clean-test clean-overlay-images clean-bootcycle-build
.PHONY: profiles profiles-only profiles-oscheck

View File

@ -225,3 +225,5 @@ c8286839d0df04aba819ec4bef12b86babccf30e jdk8-b90
a013024b07475782f1fa8e196e950b34b4077663 jdk8-b101
528c7e76eaeee022817ee085668459bc97cf5665 jdk8-b102
49c4a777fdfd648d4c3fffc940fdb97a23108ca8 jdk8-b103
d411c60a8c2fe8fdc572af907775e90f7eefd513 jdk8-b104
4e38de7c767e34104fa147b5b346d9fe6b731279 jdk8-b105

View File

@ -369,3 +369,7 @@ c4697c1c448416108743b59118b4a2498b339d0c jdk8-b102
7f55137d6aa81efc6eb0035813709f2cb6a26b8b hs25-b45
6f9be7f87b9653e94fd8fb3070891a0cc91b15bf jdk8-b103
580430d131ccd475e2f2ad4006531b8c4813d102 hs25-b46
104743074675359cfbf7f4dcd9ab2a5974a16627 jdk8-b104
c1604d5885a6f2adc0bcea2fa142a8f6bafad2f0 hs25-b47
acac3bde66b2c22791c257a8d99611d6d08c6713 jdk8-b105
18b4798adbc42c6fa16f5ecb7d5cd3ca130754bf hs25-b48

View File

@ -75,19 +75,19 @@ public class InstanceKlass extends Klass {
javaFieldsCount = new CIntField(type.getCIntegerField("_java_fields_count"), 0);
constants = new MetadataField(type.getAddressField("_constants"), 0);
classLoaderData = type.getAddressField("_class_loader_data");
sourceFileName = type.getAddressField("_source_file_name");
sourceDebugExtension = type.getAddressField("_source_debug_extension");
innerClasses = type.getAddressField("_inner_classes");
sourceFileNameIndex = new CIntField(type.getCIntegerField("_source_file_name_index"), 0);
nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), 0);
staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), 0);
staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0);
staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0);
nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), 0);
isMarkedDependent = new CIntField(type.getCIntegerField("_is_marked_dependent"), 0);
initState = new CIntField(type.getCIntegerField("_init_state"), 0);
vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), 0);
itableLen = new CIntField(type.getCIntegerField("_itable_len"), 0);
breakpoints = type.getAddressField("_breakpoints");
genericSignature = type.getAddressField("_generic_signature");
genericSignatureIndex = new CIntField(type.getCIntegerField("_generic_signature_index"), 0);
majorVersion = new CIntField(type.getCIntegerField("_major_version"), 0);
minorVersion = new CIntField(type.getCIntegerField("_minor_version"), 0);
headerSize = Oop.alignObjectOffset(type.getSize());
@ -134,9 +134,9 @@ public class InstanceKlass extends Klass {
private static CIntField javaFieldsCount;
private static MetadataField constants;
private static AddressField classLoaderData;
private static AddressField sourceFileName;
private static AddressField sourceDebugExtension;
private static AddressField innerClasses;
private static CIntField sourceFileNameIndex;
private static CIntField nonstaticFieldSize;
private static CIntField staticFieldSize;
private static CIntField staticOopFieldCount;
@ -146,7 +146,7 @@ public class InstanceKlass extends Klass {
private static CIntField vtableLen;
private static CIntField itableLen;
private static AddressField breakpoints;
private static AddressField genericSignature;
private static CIntField genericSignatureIndex;
private static CIntField majorVersion;
private static CIntField minorVersion;
@ -346,7 +346,7 @@ public class InstanceKlass extends Klass {
public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); }
public ClassLoaderData getClassLoaderData() { return ClassLoaderData.instantiateWrapperFor(classLoaderData.getValue(getAddress())); }
public Oop getClassLoader() { return getClassLoaderData().getClassLoader(); }
public Symbol getSourceFileName() { return getSymbol(sourceFileName); }
public Symbol getSourceFileName() { return getConstants().getSymbolAt(sourceFileNameIndex.getValue(this)); }
public String getSourceDebugExtension(){ return CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); }
public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); }
public long getStaticOopFieldCount() { return staticOopFieldCount.getValue(this); }
@ -354,7 +354,7 @@ public class InstanceKlass extends Klass {
public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; }
public long getVtableLen() { return vtableLen.getValue(this); }
public long getItableLen() { return itableLen.getValue(this); }
public Symbol getGenericSignature() { return getSymbol(genericSignature); }
public Symbol getGenericSignature() { return getConstants().getSymbolAt(genericSignatureIndex.getValue(this)); }
public long majorVersion() { return majorVersion.getValue(this); }
public long minorVersion() { return minorVersion.getValue(this); }

View File

@ -92,8 +92,13 @@ public class ClassDump extends Tool {
System.err.println("Warning: Can not create class filter!");
}
}
String outputDirectory = System.getProperty("sun.jvm.hotspot.tools.jcore.outputDir", ".");
setOutputDirectory(outputDirectory);
// outputDirectory and jarStream are alternatives: setting one closes the other.
// If neither is set, use outputDirectory from the System property:
if (outputDirectory == null && jarStream == null) {
String dirName = System.getProperty("sun.jvm.hotspot.tools.jcore.outputDir", ".");
setOutputDirectory(dirName);
}
// walk through the system dictionary
SystemDictionary dict = VM.getVM().getSystemDictionary();

View File

@ -35,8 +35,9 @@ sapkg.c1 = sapkg.hotspot.c1;
sapkg.code = sapkg.hotspot.code;
sapkg.compiler = sapkg.hotspot.compiler;
// 'debugger' is a JavaScript keyword :-(
// sapkg.debugger = sapkg.hotspot.debugger;
// 'debugger' is a JavaScript keyword, but ES5 relaxes the
// restriction of using keywords as property name
sapkg.debugger = sapkg.hotspot.debugger;
sapkg.interpreter = sapkg.hotspot.interpreter;
sapkg.jdi = sapkg.hotspot.jdi;
@ -116,27 +117,36 @@ function main(globals, jvmarg) {
return args;
}
// Handle __has__ specially to avoid metacircularity problems
// when called from __get__.
// Calling
// this.__has__(name)
// will in turn call
// this.__call__('__has__', name)
// which is not handled below
function __has__(name) {
if (typeof(name) == 'number') {
return so["has(int)"](name);
} else {
if (name == '__wrapped__') {
return true;
} else if (so["has(java.lang.String)"](name)) {
return true;
} else if (name.equals('toString')) {
return true;
} else {
return false;
}
}
}
if (so instanceof sapkg.utilities.soql.ScriptObject) {
return new JSAdapter() {
__getIds__: function() {
return so.getIds();
__getIds__: function() {
return so.getIds();
},
__has__ : function(name) {
if (typeof(name) == 'number') {
return so["has(int)"](name);
} else {
if (name == '__wrapped__') {
return true;
} else if (so["has(java.lang.String)"](name)) {
return true;
} else if (name.equals('toString')) {
return true;
} else {
return false;
}
}
},
__has__ : __has__,
__delete__ : function(name) {
if (typeof(name) == 'number') {
@ -147,7 +157,8 @@ function main(globals, jvmarg) {
},
__get__ : function(name) {
if (! this.__has__(name)) {
// don't call this.__has__(name); see comments above function __has__
if (! __has__.call(this, name)) {
return undefined;
}
if (typeof(name) == 'number') {
@ -162,7 +173,7 @@ function main(globals, jvmarg) {
var args = prepareArgsArray(arguments);
var r;
try {
r = value.call(args);
r = value.call(Java.to(args, 'java.lang.Object[]'));
} catch (e) {
println("call to " + name + " failed!");
throw e;
@ -204,6 +215,18 @@ function main(globals, jvmarg) {
}
// define "writeln" and "write" if not defined
if (typeof(println) == 'undefined') {
println = function (str) {
java.lang.System.out.println(String(str));
}
}
if (typeof(print) == 'undefined') {
print = function (str) {
java.lang.System.out.print(String(str));
}
}
if (typeof(writeln) == 'undefined') {
writeln = println;
}
@ -235,7 +258,7 @@ function main(globals, jvmarg) {
this.jclasses = function() {
forEachKlass(function (clazz) {
writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString());
writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString());
});
}
registerCommand("classes", "classes", "jclasses");
@ -490,14 +513,14 @@ function systemLoader() {
function forEachKlass(callback) {
var VisitorClass = sapkg.memory.SystemDictionary.ClassVisitor;
var visitor = new VisitorClass() { visit: callback };
sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassVisitor)"](visitor);
sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassVisitor)"](visitor);
}
// iterate system dictionary for each 'Klass' and initiating loader
function forEachKlassAndLoader(callback) {
var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor;
var visitor = new VisitorClass() { visit: callback };
sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassAndLoaderVisitor)"](visitor);
sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassAndLoaderVisitor)"](visitor);
}
// iterate system dictionary for each primitive array klass
@ -522,7 +545,12 @@ function obj2oop(obj) {
// iterates Java heap for each Oop
function forEachOop(callback) {
sa.objHeap.iterate(new sapkg.oops.HeapVisitor() { doObj: callback });
function empty() { }
sa.objHeap.iterate(new sapkg.oops.HeapVisitor() {
prologue: empty,
doObj: callback,
epilogue: empty
});
}
// iterates Java heap for each Oop of given 'klass'.
@ -536,8 +564,14 @@ function forEachOopOfKlass(callback, klass, includeSubtypes) {
if (includeSubtypes == undefined) {
includeSubtypes = true;
}
function empty() { }
sa.objHeap.iterateObjectsOfKlass(
new sapkg.oops.HeapVisitor() { doObj: callback },
new sapkg.oops.HeapVisitor() {
prologue: empty,
doObj: callback,
epilogue: empty
},
klass, includeSubtypes);
}
@ -746,9 +780,9 @@ while (tmp.itr.hasNext()) {
// ignore;
continue;
} else {
// some type names have ':'. replace to make it as a
// some type names have ':', '<', '>', '*', ' '. replace to make it as a
// JavaScript identifier
tmp.name = tmp.name.replace(':', '_').replace('<', '_').replace('>', '_').replace('*', '_').replace(' ', '_');
tmp.name = ("" + tmp.name).replace(/[:<>* ]/g, '_');
eval("function read" + tmp.name + "(addr) {" +
" return readVMType('" + tmp.name + "', addr);}");
eval("function print" + tmp.name + "(addr) {" +

View File

@ -247,7 +247,7 @@ ifeq ($(USE_CLANG), true)
# Not yet supported by clang in Xcode 4.6.2
# WARNINGS_ARE_ERRORS += -Wno-tautological-constant-out-of-range-compare
WARNINGS_ARE_ERRORS += -Wno-delete-non-virtual-dtor -Wno-deprecated -Wno-format -Wno-dynamic-class-memaccess
WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body
WARNINGS_ARE_ERRORS += -Wno-empty-body
endif
WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef

View File

@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013
HS_MAJOR_VER=25
HS_MINOR_VER=0
HS_BUILD_NUMBER=46
HS_BUILD_NUMBER=48
JDK_MAJOR_VER=1
JDK_MINOR_VER=8

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -31,9 +31,4 @@ CFLAGS += -DVM_LITTLE_ENDIAN
CFLAGS += -D_LP64=1
# The serviceability agent relies on frame pointer (%rbp) to walk thread stack
ifndef USE_SUNCC
CFLAGS += -fno-omit-frame-pointer
endif
OPT_CFLAGS/compactingPermGenGen.o = -O1

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -398,3 +398,10 @@ endif
ifdef MINIMIZE_RAM_USAGE
CFLAGS += -DMINIMIZE_RAM_USAGE
endif
# Stack walking in the JVM relies on frame pointer (%rbp) to walk thread stack.
# Explicitly specify -fno-omit-frame-pointer because it is off by default
# starting with gcc 4.6.
ifndef USE_SUNCC
CFLAGS += -fno-omit-frame-pointer
endif

View File

@ -42,8 +42,6 @@ else
MKS_HOME=`dirname "$SH"`
fi
echo "EXPORTS" > vm1.def
AWK="$MKS_HOME/awk.exe"
if [ ! -e $AWK ]; then
AWK="$MKS_HOME/gawk.exe"
@ -55,6 +53,22 @@ CAT="$MKS_HOME/cat.exe"
RM="$MKS_HOME/rm.exe"
DUMPBIN="link.exe /dump"
if [ "$1" = "-nosa" ]; then
echo EXPORTS > vm.def
echo ""
echo "***"
echo "*** Not building SA: BUILD_WIN_SA != 1"
echo "*** C++ Vtables NOT included in vm.def"
echo "*** This jvm.dll will NOT work properly with SA."
echo "***"
echo "*** When in doubt, set BUILD_WIN_SA=1, clean and rebuild."
echo "***"
echo ""
exit
fi
echo "EXPORTS" > vm1.def
# When called from IDE the first param should contain the link version, otherwise may be nill
if [ "x$1" != "x" ]; then
LD_VER="$1"

View File

@ -49,9 +49,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)-debug
# Force resources to be rebuilt every time
$(Res_Files): FORCE
vm.def: $(Obj_Files)
sh $(WorkSpace)/make/windows/build_vm_def.sh
$(AOUT): $(Res_Files) $(Obj_Files) vm.def
$(LD) @<<
$(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)

View File

@ -48,9 +48,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)-fastdebug
# Force resources to be rebuilt every time
$(Res_Files): FORCE
vm.def: $(Obj_Files)
sh $(WorkSpace)/make/windows/build_vm_def.sh
$(AOUT): $(Res_Files) $(Obj_Files) vm.def
$(LD) @<<
$(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)

View File

@ -51,9 +51,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)
# Force resources to be rebuilt every time
$(Res_Files): FORCE
vm.def: $(Obj_Files)
sh $(WorkSpace)/make/windows/build_vm_def.sh
$(AOUT): $(Res_Files) $(Obj_Files) vm.def
$(LD) @<<
$(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files)

View File

@ -92,6 +92,10 @@ ProjectCreatorIDEOptions = \
-disablePch getThread_windows_$(Platform_arch).cpp \
-disablePch_compiler2 opcodes.cpp
!if "$(BUILD_WIN_SA)" != "1"
BUILD_VM_DEF_FLAG=-nosa
!endif
# Common options for the IDE builds for c1, and c2
ProjectCreatorIDEOptions=\
$(ProjectCreatorIDEOptions) \
@ -104,7 +108,7 @@ ProjectCreatorIDEOptions=\
-jdkTargetRoot $(HOTSPOTJDKDIST) \
-define ALIGN_STACK_FRAMES \
-define VM_LITTLE_ENDIAN \
-prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LD_VER)" \
-prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(BUILD_VM_DEF_FLAG) $(LD_VER)" \
-ignoreFile jsig.c \
-ignoreFile jvmtiEnvRecommended.cpp \
-ignoreFile jvmtiEnvStub.cpp \

View File

@ -393,3 +393,11 @@ default::
_build_pch_file.obj:
@echo #include "precompiled.hpp" > ../generated/_build_pch_file.cpp
$(CXX) $(CXX_FLAGS) /Fp"vm.pch" /Yc"precompiled.hpp" /c ../generated/_build_pch_file.cpp
!if "$(BUILD_WIN_SA)" != "1"
BUILD_VM_DEF_FLAG=-nosa
!endif
vm.def: $(Obj_Files)
sh $(WorkSpace)/make/windows/build_vm_def.sh $(BUILD_VM_DEF_FLAG)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,6 +29,7 @@
#include "interpreter/interpreter.hpp"
#include "memory/cardTableModRefBS.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/interfaceSupport.hpp"
@ -1145,7 +1146,7 @@ void MacroAssembler::set_narrow_klass(Klass* k, Register d) {
assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
int klass_index = oop_recorder()->find_index(k);
RelocationHolder rspec = metadata_Relocation::spec(klass_index);
narrowOop encoded_k = oopDesc::encode_klass(k);
narrowOop encoded_k = Klass::encode_klass(k);
assert_not_delayed();
// Relocation with special format (see relocInfo_sparc.hpp).
@ -1419,7 +1420,6 @@ void MacroAssembler::verify_oop_subroutine() {
load_klass(O0_obj, O0_obj);
// assert((klass != NULL)
br_null_short(O0_obj, pn, fail);
// TODO: Future assert that klass is lower 4g memory for UseCompressedKlassPointers
wrccr( O5_save_flags ); // Restore CCR's
@ -4089,52 +4089,91 @@ void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) {
}
void MacroAssembler::encode_klass_not_null(Register r) {
assert(Metaspace::is_initialized(), "metaspace should be initialized");
assert (UseCompressedKlassPointers, "must be compressed");
assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
if (Universe::narrow_klass_base() != NULL)
sub(r, G6_heapbase, r);
srlx(r, LogKlassAlignmentInBytes, r);
assert(Universe::narrow_klass_base() != NULL, "narrow_klass_base should be initialized");
assert(r != G6_heapbase, "bad register choice");
set((intptr_t)Universe::narrow_klass_base(), G6_heapbase);
sub(r, G6_heapbase, r);
if (Universe::narrow_klass_shift() != 0) {
assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
srlx(r, LogKlassAlignmentInBytes, r);
}
reinit_heapbase();
}
void MacroAssembler::encode_klass_not_null(Register src, Register dst) {
assert(Metaspace::is_initialized(), "metaspace should be initialized");
assert (UseCompressedKlassPointers, "must be compressed");
assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
if (Universe::narrow_klass_base() == NULL) {
srlx(src, LogKlassAlignmentInBytes, dst);
if (src == dst) {
encode_klass_not_null(src);
} else {
sub(src, G6_heapbase, dst);
srlx(dst, LogKlassAlignmentInBytes, dst);
assert (UseCompressedKlassPointers, "must be compressed");
assert(Universe::narrow_klass_base() != NULL, "narrow_klass_base should be initialized");
set((intptr_t)Universe::narrow_klass_base(), dst);
sub(src, dst, dst);
if (Universe::narrow_klass_shift() != 0) {
srlx(dst, LogKlassAlignmentInBytes, dst);
}
}
}
// Function instr_size_for_decode_klass_not_null() counts the instructions
// generated by decode_klass_not_null() and reinit_heapbase(). Hence, if
// the instructions they generate change, then this method needs to be updated.
int MacroAssembler::instr_size_for_decode_klass_not_null() {
assert (UseCompressedKlassPointers, "only for compressed klass ptrs");
// set + add + set
int num_instrs = insts_for_internal_set((intptr_t)Universe::narrow_klass_base()) + 1 +
insts_for_internal_set((intptr_t)Universe::narrow_ptrs_base());
if (Universe::narrow_klass_shift() == 0) {
return num_instrs * BytesPerInstWord;
} else { // sllx
return (num_instrs + 1) * BytesPerInstWord;
}
}
// !!! If the instructions that get generated here change then function
// instr_size_for_decode_klass_not_null() needs to get updated.
void MacroAssembler::decode_klass_not_null(Register r) {
assert(Metaspace::is_initialized(), "metaspace should be initialized");
// Do not add assert code to this unless you change vtableStubs_sparc.cpp
// pd_code_size_limit.
assert (UseCompressedKlassPointers, "must be compressed");
assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
sllx(r, LogKlassAlignmentInBytes, r);
if (Universe::narrow_klass_base() != NULL)
add(r, G6_heapbase, r);
assert(Universe::narrow_klass_base() != NULL, "narrow_klass_base should be initialized");
assert(r != G6_heapbase, "bad register choice");
set((intptr_t)Universe::narrow_klass_base(), G6_heapbase);
if (Universe::narrow_klass_shift() != 0)
sllx(r, LogKlassAlignmentInBytes, r);
add(r, G6_heapbase, r);
reinit_heapbase();
}
void MacroAssembler::decode_klass_not_null(Register src, Register dst) {
assert(Metaspace::is_initialized(), "metaspace should be initialized");
// Do not add assert code to this unless you change vtableStubs_sparc.cpp
// pd_code_size_limit.
assert (UseCompressedKlassPointers, "must be compressed");
assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
sllx(src, LogKlassAlignmentInBytes, dst);
if (Universe::narrow_klass_base() != NULL)
add(dst, G6_heapbase, dst);
if (src == dst) {
decode_klass_not_null(src);
} else {
// Do not add assert code to this unless you change vtableStubs_sparc.cpp
// pd_code_size_limit.
assert (UseCompressedKlassPointers, "must be compressed");
assert(Universe::narrow_klass_base() != NULL, "narrow_klass_base should be initialized");
if (Universe::narrow_klass_shift() != 0) {
assert((src != G6_heapbase) && (dst != G6_heapbase), "bad register choice");
set((intptr_t)Universe::narrow_klass_base(), G6_heapbase);
sllx(src, LogKlassAlignmentInBytes, dst);
add(dst, G6_heapbase, dst);
reinit_heapbase();
} else {
set((intptr_t)Universe::narrow_klass_base(), dst);
add(src, dst, dst);
}
}
}
void MacroAssembler::reinit_heapbase() {
if (UseCompressedOops || UseCompressedKlassPointers) {
AddressLiteral base(Universe::narrow_ptrs_base_addr());
load_ptr_contents(base, G6_heapbase);
if (Universe::heap() != NULL) {
set((intptr_t)Universe::narrow_ptrs_base(), G6_heapbase);
} else {
AddressLiteral base(Universe::narrow_ptrs_base_addr());
load_ptr_contents(base, G6_heapbase);
}
}
}

View File

@ -1177,6 +1177,9 @@ public:
void push_CPU_state();
void pop_CPU_state();
// Returns the byte size of the instructions generated by decode_klass_not_null().
static int instr_size_for_decode_klass_not_null();
// if heap base register is used - reinit it with the correct value
void reinit_heapbase();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -97,7 +97,7 @@ void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) {
guarantee(Assembler::inv_op2(inst)==Assembler::sethi_op2, "must be sethi");
if (format() != 0) {
assert(type() == relocInfo::oop_type || type() == relocInfo::metadata_type, "only narrow oops or klasses case");
jint np = type() == relocInfo::oop_type ? oopDesc::encode_heap_oop((oop)x) : oopDesc::encode_klass((Klass*)x);
jint np = type() == relocInfo::oop_type ? oopDesc::encode_heap_oop((oop)x) : Klass::encode_klass((Klass*)x);
inst &= ~Assembler::hi22(-1);
inst |= Assembler::hi22((intptr_t)np);
if (verify_only) {

View File

@ -559,10 +559,7 @@ int MachCallDynamicJavaNode::ret_addr_offset() {
int klass_load_size;
if (UseCompressedKlassPointers) {
assert(Universe::heap() != NULL, "java heap should be initialized");
if (Universe::narrow_klass_base() == NULL)
klass_load_size = 2*BytesPerInstWord; // see MacroAssembler::load_klass()
else
klass_load_size = 3*BytesPerInstWord;
klass_load_size = MacroAssembler::instr_size_for_decode_klass_not_null() + 1*BytesPerInstWord;
} else {
klass_load_size = 1*BytesPerInstWord;
}
@ -1663,9 +1660,12 @@ void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const {
if (UseCompressedKlassPointers) {
assert(Universe::heap() != NULL, "java heap should be initialized");
st->print_cr("\tLDUW [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check - compressed klass");
st->print_cr("\tSLL R_G5,3,R_G5");
if (Universe::narrow_klass_base() != NULL)
st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5");
st->print_cr("\tSET Universe::narrow_klass_base,R_G6_heap_base");
if (Universe::narrow_klass_shift() != 0) {
st->print_cr("\tSLL R_G5,3,R_G5");
}
st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5");
st->print_cr("\tSET Universe::narrow_ptrs_base,R_G6_heap_base");
} else {
st->print_cr("\tLDX [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check");
}
@ -2563,10 +2563,7 @@ encode %{
int klass_load_size;
if (UseCompressedKlassPointers) {
assert(Universe::heap() != NULL, "java heap should be initialized");
if (Universe::narrow_klass_base() == NULL)
klass_load_size = 2*BytesPerInstWord;
else
klass_load_size = 3*BytesPerInstWord;
klass_load_size = MacroAssembler::instr_size_for_decode_klass_not_null() + 1*BytesPerInstWord;
} else {
klass_load_size = 1*BytesPerInstWord;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -219,13 +219,13 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
const int basic = 5*BytesPerInstWord +
// shift;add for load_klass (only shift with zero heap based)
(UseCompressedKlassPointers ?
((Universe::narrow_klass_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0);
MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
return basic + slop;
} else {
const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord +
// shift;add for load_klass (only shift with zero heap based)
(UseCompressedKlassPointers ?
((Universe::narrow_klass_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0);
MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
return (basic + slop);
}
}

View File

@ -30,6 +30,7 @@
#include "interpreter/interpreter.hpp"
#include "memory/cardTableModRefBS.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/interfaceSupport.hpp"
@ -4810,23 +4811,8 @@ void MacroAssembler::load_klass(Register dst, Register src) {
}
void MacroAssembler::load_prototype_header(Register dst, Register src) {
#ifdef _LP64
if (UseCompressedKlassPointers) {
assert (Universe::heap() != NULL, "java heap should be initialized");
movl(dst, Address(src, oopDesc::klass_offset_in_bytes()));
if (Universe::narrow_klass_shift() != 0) {
assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?");
movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset()));
} else {
movq(dst, Address(dst, Klass::prototype_header_offset()));
}
} else
#endif
{
movptr(dst, Address(src, oopDesc::klass_offset_in_bytes()));
movptr(dst, Address(dst, Klass::prototype_header_offset()));
}
load_klass(dst, src);
movptr(dst, Address(dst, Klass::prototype_header_offset()));
}
void MacroAssembler::store_klass(Register dst, Register src) {
@ -4914,7 +4900,7 @@ void MacroAssembler::store_klass_gap(Register dst, Register src) {
#ifdef ASSERT
void MacroAssembler::verify_heapbase(const char* msg) {
assert (UseCompressedOops || UseCompressedKlassPointers, "should be compressed");
assert (UseCompressedOops, "should be compressed");
assert (Universe::heap() != NULL, "java heap should be initialized");
if (CheckCompressedOops) {
Label ok;
@ -5058,69 +5044,80 @@ void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) {
}
void MacroAssembler::encode_klass_not_null(Register r) {
assert(Metaspace::is_initialized(), "metaspace should be initialized");
#ifdef ASSERT
verify_heapbase("MacroAssembler::encode_klass_not_null: heap base corrupted?");
#endif
if (Universe::narrow_klass_base() != NULL) {
subq(r, r12_heapbase);
}
assert(Universe::narrow_klass_base() != NULL, "Base should be initialized");
// Use r12 as a scratch register in which to temporarily load the narrow_klass_base.
assert(r != r12_heapbase, "Encoding a klass in r12");
mov64(r12_heapbase, (int64_t)Universe::narrow_klass_base());
subq(r, r12_heapbase);
if (Universe::narrow_klass_shift() != 0) {
assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
shrq(r, LogKlassAlignmentInBytes);
}
reinit_heapbase();
}
void MacroAssembler::encode_klass_not_null(Register dst, Register src) {
assert(Metaspace::is_initialized(), "metaspace should be initialized");
#ifdef ASSERT
verify_heapbase("MacroAssembler::encode_klass_not_null2: heap base corrupted?");
#endif
if (dst != src) {
movq(dst, src);
}
if (Universe::narrow_klass_base() != NULL) {
subq(dst, r12_heapbase);
}
if (Universe::narrow_klass_shift() != 0) {
assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
shrq(dst, LogKlassAlignmentInBytes);
if (dst == src) {
encode_klass_not_null(src);
} else {
mov64(dst, (int64_t)Universe::narrow_klass_base());
negq(dst);
addq(dst, src);
if (Universe::narrow_klass_shift() != 0) {
assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
shrq(dst, LogKlassAlignmentInBytes);
}
}
}
// Function instr_size_for_decode_klass_not_null() counts the instructions
// generated by decode_klass_not_null(register r) and reinit_heapbase(),
// when (Universe::heap() != NULL). Hence, if the instructions they
// generate change, then this method needs to be updated.
int MacroAssembler::instr_size_for_decode_klass_not_null() {
assert (UseCompressedKlassPointers, "only for compressed klass ptrs");
// mov64 + addq + shlq? + mov64 (for reinit_heapbase()).
return (Universe::narrow_klass_shift() == 0 ? 20 : 24);
}
// !!! If the instructions that get generated here change then function
// instr_size_for_decode_klass_not_null() needs to get updated.
void MacroAssembler::decode_klass_not_null(Register r) {
assert(Metaspace::is_initialized(), "metaspace should be initialized");
// Note: it will change flags
assert(Universe::narrow_klass_base() != NULL, "Base should be initialized");
assert (UseCompressedKlassPointers, "should only be used for compressed headers");
assert(r != r12_heapbase, "Decoding a klass in r12");
// Cannot assert, unverified entry point counts instructions (see .ad file)
// vtableStubs also counts instructions in pd_code_size_limit.
// Also do not verify_oop as this is called by verify_oop.
if (Universe::narrow_klass_shift() != 0) {
assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
shlq(r, LogKlassAlignmentInBytes);
if (Universe::narrow_klass_base() != NULL) {
addq(r, r12_heapbase);
}
} else {
assert (Universe::narrow_klass_base() == NULL, "sanity");
}
// Use r12 as a scratch register in which to temporarily load the narrow_klass_base.
mov64(r12_heapbase, (int64_t)Universe::narrow_klass_base());
addq(r, r12_heapbase);
reinit_heapbase();
}
void MacroAssembler::decode_klass_not_null(Register dst, Register src) {
assert(Metaspace::is_initialized(), "metaspace should be initialized");
// Note: it will change flags
assert(Universe::narrow_klass_base() != NULL, "Base should be initialized");
assert (UseCompressedKlassPointers, "should only be used for compressed headers");
// Cannot assert, unverified entry point counts instructions (see .ad file)
// vtableStubs also counts instructions in pd_code_size_limit.
// Also do not verify_oop as this is called by verify_oop.
if (Universe::narrow_klass_shift() != 0) {
assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?");
leaq(dst, Address(r12_heapbase, src, Address::times_8, 0));
if (dst == src) {
decode_klass_not_null(dst);
} else {
assert (Universe::narrow_klass_base() == NULL, "sanity");
if (dst != src) {
movq(dst, src);
// Cannot assert, unverified entry point counts instructions (see .ad file)
// vtableStubs also counts instructions in pd_code_size_limit.
// Also do not verify_oop as this is called by verify_oop.
mov64(dst, (int64_t)Universe::narrow_klass_base());
if (Universe::narrow_klass_shift() != 0) {
assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?");
leaq(dst, Address(dst, src, Address::times_8, 0));
} else {
addq(dst, src);
}
}
}
@ -5148,7 +5145,7 @@ void MacroAssembler::set_narrow_klass(Register dst, Klass* k) {
assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
int klass_index = oop_recorder()->find_index(k);
RelocationHolder rspec = metadata_Relocation::spec(klass_index);
mov_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
mov_narrow_oop(dst, Klass::encode_klass(k), rspec);
}
void MacroAssembler::set_narrow_klass(Address dst, Klass* k) {
@ -5156,7 +5153,7 @@ void MacroAssembler::set_narrow_klass(Address dst, Klass* k) {
assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
int klass_index = oop_recorder()->find_index(k);
RelocationHolder rspec = metadata_Relocation::spec(klass_index);
mov_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
mov_narrow_oop(dst, Klass::encode_klass(k), rspec);
}
void MacroAssembler::cmp_narrow_oop(Register dst, jobject obj) {
@ -5182,7 +5179,7 @@ void MacroAssembler::cmp_narrow_klass(Register dst, Klass* k) {
assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
int klass_index = oop_recorder()->find_index(k);
RelocationHolder rspec = metadata_Relocation::spec(klass_index);
Assembler::cmp_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
Assembler::cmp_narrow_oop(dst, Klass::encode_klass(k), rspec);
}
void MacroAssembler::cmp_narrow_klass(Address dst, Klass* k) {
@ -5190,14 +5187,23 @@ void MacroAssembler::cmp_narrow_klass(Address dst, Klass* k) {
assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
int klass_index = oop_recorder()->find_index(k);
RelocationHolder rspec = metadata_Relocation::spec(klass_index);
Assembler::cmp_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
Assembler::cmp_narrow_oop(dst, Klass::encode_klass(k), rspec);
}
void MacroAssembler::reinit_heapbase() {
if (UseCompressedOops || UseCompressedKlassPointers) {
movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr()));
if (Universe::heap() != NULL) {
if (Universe::narrow_oop_base() == NULL) {
MacroAssembler::xorptr(r12_heapbase, r12_heapbase);
} else {
mov64(r12_heapbase, (int64_t)Universe::narrow_ptrs_base());
}
} else {
movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr()));
}
}
}
#endif // _LP64

View File

@ -371,6 +371,10 @@ class MacroAssembler: public Assembler {
void cmp_narrow_klass(Register dst, Klass* k);
void cmp_narrow_klass(Address dst, Klass* k);
// Returns the byte size of the instructions generated by decode_klass_not_null()
// when compressed klass pointers are being used.
static int instr_size_for_decode_klass_not_null();
// if heap base register is used - reinit it with the correct value
void reinit_heapbase();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -55,9 +55,9 @@ void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) {
}
} else {
if (verify_only) {
assert(*(uint32_t*) disp == oopDesc::encode_klass((Klass*)x), "instructions must match");
assert(*(uint32_t*) disp == Klass::encode_klass((Klass*)x), "instructions must match");
} else {
*(int32_t*) disp = oopDesc::encode_klass((Klass*)x);
*(int32_t*) disp = Klass::encode_klass((Klass*)x);
}
}
} else {

View File

@ -675,7 +675,6 @@ class StubGenerator: public StubCodeGenerator {
__ movptr(rax, Address(rax, oopDesc::klass_offset_in_bytes())); // get klass
__ testptr(rax, rax);
__ jcc(Assembler::zero, error); // if klass is NULL it is broken
// TODO: Future assert that klass is lower 4g memory for UseCompressedKlassPointers
// return if everything seems ok
__ bind(exit);

View File

@ -1021,7 +1021,6 @@ class StubGenerator: public StubCodeGenerator {
__ load_klass(rax, rax); // get klass
__ testptr(rax, rax);
__ jcc(Assembler::zero, error); // if klass is NULL it is broken
// TODO: Future assert that klass is lower 4g memory for UseCompressedKlassPointers
// return if everything seems ok
__ bind(exit);

View File

@ -849,9 +849,9 @@ address InterpreterGenerator::generate_CRC32_update_entry() {
address entry = __ pc();
// rbx,: Method*
// rsi: senderSP must preserved for slow path, set SP to it on fast path
// rdx: scratch
// rdi: scratch
// r13: senderSP must preserved for slow path, set SP to it on fast path
// c_rarg0: scratch (rdi on non-Win64, rcx on Win64)
// c_rarg1: scratch (rsi on non-Win64, rdx on Win64)
Label slow_path;
// If we need a safepoint check, generate full interpreter entry.
@ -865,8 +865,8 @@ address InterpreterGenerator::generate_CRC32_update_entry() {
// Load parameters
const Register crc = rax; // crc
const Register val = rdx; // source java byte value
const Register tbl = rdi; // scratch
const Register val = c_rarg0; // source java byte value
const Register tbl = c_rarg1; // scratch
// Arguments are reversed on java expression stack
__ movl(val, Address(rsp, wordSize)); // byte value
@ -880,7 +880,7 @@ address InterpreterGenerator::generate_CRC32_update_entry() {
// _areturn
__ pop(rdi); // get return address
__ mov(rsp, rsi); // set sp to sender sp
__ mov(rsp, r13); // set sp to sender sp
__ jmp(rdi);
// generate a vanilla native entry as the slow path
@ -919,20 +919,24 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret
const Register crc = c_rarg0; // crc
const Register buf = c_rarg1; // source java byte array address
const Register len = c_rarg2; // length
const Register off = len; // offset (never overlaps with 'len')
// Arguments are reversed on java expression stack
__ movl(len, Address(rsp, wordSize)); // Length
// Calculate address of start element
if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) {
__ movptr(buf, Address(rsp, 3*wordSize)); // long buf
__ addptr(buf, Address(rsp, 2*wordSize)); // + offset
__ movl2ptr(off, Address(rsp, 2*wordSize)); // offset
__ addq(buf, off); // + offset
__ movl(crc, Address(rsp, 5*wordSize)); // Initial CRC
} else {
__ movptr(buf, Address(rsp, 3*wordSize)); // byte[] array
__ addptr(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // + header size
__ addptr(buf, Address(rsp, 2*wordSize)); // + offset
__ movl2ptr(off, Address(rsp, 2*wordSize)); // offset
__ addq(buf, off); // + offset
__ movl(crc, Address(rsp, 4*wordSize)); // Initial CRC
}
// Can now load 'len' since we're finished with 'off'
__ movl(len, Address(rsp, wordSize)); // Length
__ super_call_VM_leaf(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32()), crc, buf, len);
// result in rax

View File

@ -211,11 +211,11 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
if (is_vtable_stub) {
// Vtable stub size
return (DebugVtables ? 512 : 24) + (CountCompiledCalls ? 13 : 0) +
(UseCompressedKlassPointers ? 16 : 0); // 1 leaq can be 3 bytes + 1 long
(UseCompressedKlassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
} else {
// Itable stub size
return (DebugVtables ? 512 : 74) + (CountCompiledCalls ? 13 : 0) +
(UseCompressedKlassPointers ? 32 : 0); // 2 leaqs
(UseCompressedKlassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0);
}
// In order to tune these parameters, run the JVM with VM options
// +PrintMiscellaneous and +WizardMode to see information about

View File

@ -1393,9 +1393,7 @@ void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const
{
if (UseCompressedKlassPointers) {
st->print_cr("movl rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass");
if (Universe::narrow_klass_shift() != 0) {
st->print_cr("\tdecode_klass_not_null rscratch1, rscratch1");
}
st->print_cr("\tdecode_klass_not_null rscratch1, rscratch1");
st->print_cr("\tcmpq rax, rscratch1\t # Inline cache check");
} else {
st->print_cr("\tcmpq rax, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t"
@ -4035,146 +4033,6 @@ operand indPosIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegI idx, immI2 sca
%}
%}
operand indirectNarrowKlass(rRegN reg)
%{
predicate(Universe::narrow_klass_shift() == 0);
constraint(ALLOC_IN_RC(ptr_reg));
match(DecodeNKlass reg);
format %{ "[$reg]" %}
interface(MEMORY_INTER) %{
base($reg);
index(0x4);
scale(0x0);
disp(0x0);
%}
%}
operand indOffset8NarrowKlass(rRegN reg, immL8 off)
%{
predicate(Universe::narrow_klass_shift() == 0);
constraint(ALLOC_IN_RC(ptr_reg));
match(AddP (DecodeNKlass reg) off);
format %{ "[$reg + $off (8-bit)]" %}
interface(MEMORY_INTER) %{
base($reg);
index(0x4);
scale(0x0);
disp($off);
%}
%}
operand indOffset32NarrowKlass(rRegN reg, immL32 off)
%{
predicate(Universe::narrow_klass_shift() == 0);
constraint(ALLOC_IN_RC(ptr_reg));
match(AddP (DecodeNKlass reg) off);
format %{ "[$reg + $off (32-bit)]" %}
interface(MEMORY_INTER) %{
base($reg);
index(0x4);
scale(0x0);
disp($off);
%}
%}
operand indIndexOffsetNarrowKlass(rRegN reg, rRegL lreg, immL32 off)
%{
predicate(Universe::narrow_klass_shift() == 0);
constraint(ALLOC_IN_RC(ptr_reg));
match(AddP (AddP (DecodeNKlass reg) lreg) off);
op_cost(10);
format %{"[$reg + $off + $lreg]" %}
interface(MEMORY_INTER) %{
base($reg);
index($lreg);
scale(0x0);
disp($off);
%}
%}
operand indIndexNarrowKlass(rRegN reg, rRegL lreg)
%{
predicate(Universe::narrow_klass_shift() == 0);
constraint(ALLOC_IN_RC(ptr_reg));
match(AddP (DecodeNKlass reg) lreg);
op_cost(10);
format %{"[$reg + $lreg]" %}
interface(MEMORY_INTER) %{
base($reg);
index($lreg);
scale(0x0);
disp(0x0);
%}
%}
operand indIndexScaleNarrowKlass(rRegN reg, rRegL lreg, immI2 scale)
%{
predicate(Universe::narrow_klass_shift() == 0);
constraint(ALLOC_IN_RC(ptr_reg));
match(AddP (DecodeNKlass reg) (LShiftL lreg scale));
op_cost(10);
format %{"[$reg + $lreg << $scale]" %}
interface(MEMORY_INTER) %{
base($reg);
index($lreg);
scale($scale);
disp(0x0);
%}
%}
operand indIndexScaleOffsetNarrowKlass(rRegN reg, immL32 off, rRegL lreg, immI2 scale)
%{
predicate(Universe::narrow_klass_shift() == 0);
constraint(ALLOC_IN_RC(ptr_reg));
match(AddP (AddP (DecodeNKlass reg) (LShiftL lreg scale)) off);
op_cost(10);
format %{"[$reg + $off + $lreg << $scale]" %}
interface(MEMORY_INTER) %{
base($reg);
index($lreg);
scale($scale);
disp($off);
%}
%}
operand indCompressedKlassOffset(rRegN reg, immL32 off) %{
predicate(UseCompressedKlassPointers && (Universe::narrow_klass_shift() == Address::times_8));
constraint(ALLOC_IN_RC(ptr_reg));
match(AddP (DecodeNKlass reg) off);
op_cost(10);
format %{"[R12 + $reg << 3 + $off] (compressed klass addressing)" %}
interface(MEMORY_INTER) %{
base(0xc); // R12
index($reg);
scale(0x3);
disp($off);
%}
%}
operand indPosIndexScaleOffsetNarrowKlass(rRegN reg, immL32 off, rRegI idx, immI2 scale)
%{
constraint(ALLOC_IN_RC(ptr_reg));
predicate(Universe::narrow_klass_shift() == 0 && n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0);
match(AddP (AddP (DecodeNKlass reg) (LShiftL (ConvI2L idx) scale)) off);
op_cost(10);
format %{"[$reg + $off + $idx << $scale]" %}
interface(MEMORY_INTER) %{
base($reg);
index($idx);
scale($scale);
disp($off);
%}
%}
//----------Special Memory Operands--------------------------------------------
// Stack Slot Operand - This operand is used for loading and storing temporary
// values on the stack where a match requires a value to
@ -4345,11 +4203,7 @@ opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex,
indCompressedOopOffset,
indirectNarrow, indOffset8Narrow, indOffset32Narrow,
indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow,
indIndexScaleOffsetNarrow, indPosIndexScaleOffsetNarrow,
indCompressedKlassOffset,
indirectNarrowKlass, indOffset8NarrowKlass, indOffset32NarrowKlass,
indIndexOffsetNarrowKlass, indIndexNarrowKlass, indIndexScaleNarrowKlass,
indIndexScaleOffsetNarrowKlass, indPosIndexScaleOffsetNarrowKlass);
indIndexScaleOffsetNarrow, indPosIndexScaleOffsetNarrow);
//----------PIPELINE-----------------------------------------------------------
// Rules which define the behavior of the target architectures pipeline.
@ -6665,7 +6519,7 @@ instruct decodeHeapOop_not_null(rRegP dst, rRegN src, rFlagsReg cr) %{
instruct encodeKlass_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{
match(Set dst (EncodePKlass src));
effect(KILL cr);
format %{ "encode_heap_oop_not_null $dst,$src" %}
format %{ "encode_klass_not_null $dst,$src" %}
ins_encode %{
__ encode_klass_not_null($dst$$Register, $src$$Register);
%}
@ -6675,7 +6529,7 @@ instruct encodeKlass_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{
instruct decodeKlass_not_null(rRegP dst, rRegN src, rFlagsReg cr) %{
match(Set dst (DecodeNKlass src));
effect(KILL cr);
format %{ "decode_heap_oop_not_null $dst,$src" %}
format %{ "decode_klass_not_null $dst,$src" %}
ins_encode %{
Register s = $src$$Register;
Register d = $dst$$Register;

View File

@ -50,6 +50,7 @@ int AbstractAssembler::code_fill_byte() {
#ifdef ASSERT
bool AbstractAssembler::pd_check_instruction_mark() {
ShouldNotCallThis();
return false;
}
#endif
@ -73,6 +74,7 @@ void MacroAssembler::advance(int bytes) {
RegisterOrConstant MacroAssembler::delayed_value_impl(
intptr_t* delayed_value_addr, Register tmpl, int offset) {
ShouldNotCallThis();
return RegisterOrConstant();
}
void MacroAssembler::store_oop(jobject obj) {

View File

@ -1008,6 +1008,7 @@ void BytecodeInterpreter::layout_interpreterState(interpreterState istate,
address CppInterpreter::return_entry(TosState state, int length) {
ShouldNotCallThis();
return NULL;
}
address CppInterpreter::deopt_entry(TosState state, int length) {

View File

@ -116,6 +116,7 @@ void frame::patch_pc(Thread* thread, address pc) {
bool frame::safe_for_sender(JavaThread *thread) {
ShouldNotCallThis();
return false;
}
void frame::pd_gc_epilog() {
@ -123,6 +124,7 @@ void frame::pd_gc_epilog() {
bool frame::is_interpreted_frame_valid(JavaThread *thread) const {
ShouldNotCallThis();
return false;
}
BasicType frame::interpreter_frame_result(oop* oop_result,
@ -184,9 +186,8 @@ BasicType frame::interpreter_frame_result(oop* oop_result,
int frame::frame_size(RegisterMap* map) const {
#ifdef PRODUCT
ShouldNotCallThis();
#else
return 0; // make javaVFrame::print_value work
#endif // PRODUCT
return 0; // make javaVFrame::print_value work
}
intptr_t* frame::interpreter_frame_tos_at(jint offset) const {

View File

@ -36,7 +36,7 @@ inline frame::frame() {
_deopt_state = unknown;
}
inline address frame::sender_pc() const { ShouldNotCallThis(); }
inline address frame::sender_pc() const { ShouldNotCallThis(); return NULL; }
inline frame::frame(ZeroFrame* zf, intptr_t* sp) {
_zeroframe = zf;
@ -89,6 +89,7 @@ inline intptr_t* frame::real_fp() const {
inline intptr_t* frame::link() const {
ShouldNotCallThis();
return NULL;
}
#ifdef CC_INTERP
@ -151,14 +152,17 @@ inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
inline oop frame::saved_oop_result(RegisterMap* map) const {
ShouldNotCallThis();
return NULL;
}
inline bool frame::is_older(intptr_t* id) const {
ShouldNotCallThis();
return false;
}
inline intptr_t* frame::entry_frame_argument_at(int offset) const {
ShouldNotCallThis();
return NULL;
}
inline intptr_t* frame::unextended_sp() const {

View File

@ -49,8 +49,10 @@ void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin,
address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) {
// NB ic_stub_code_size() must return the size of the code we generate
ShouldNotCallThis();
return NULL;
}
void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) {
ShouldNotCallThis();
return NULL;
}

View File

@ -40,6 +40,7 @@ class InterpreterMacroAssembler : public MacroAssembler {
Register tmp,
int offset) {
ShouldNotCallThis();
return RegisterOrConstant();
}
};

View File

@ -64,6 +64,7 @@ address InterpreterGenerator::generate_math_entry(
return NULL;
Unimplemented();
return NULL;
}
address InterpreterGenerator::generate_abstract_entry() {

View File

@ -51,15 +51,18 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC {
public:
bool is_jump() {
ShouldNotCallThis();
return false;
}
bool is_safepoint_poll() {
ShouldNotCallThis();
return false;
}
};
inline NativeInstruction* nativeInstruction_at(address address) {
ShouldNotCallThis();
return NULL;
}
class NativeCall : public NativeInstruction {
@ -70,18 +73,22 @@ class NativeCall : public NativeInstruction {
address instruction_address() const {
ShouldNotCallThis();
return NULL;
}
address next_instruction_address() const {
ShouldNotCallThis();
return NULL;
}
address return_address() const {
ShouldNotCallThis();
return NULL;
}
address destination() const {
ShouldNotCallThis();
return NULL;
}
void set_destination_mt_safe(address dest) {
@ -98,25 +105,30 @@ class NativeCall : public NativeInstruction {
static bool is_call_before(address return_address) {
ShouldNotCallThis();
return false;
}
};
inline NativeCall* nativeCall_before(address return_address) {
ShouldNotCallThis();
return NULL;
}
inline NativeCall* nativeCall_at(address address) {
ShouldNotCallThis();
return NULL;
}
class NativeMovConstReg : public NativeInstruction {
public:
address next_instruction_address() const {
ShouldNotCallThis();
return NULL;
}
intptr_t data() const {
ShouldNotCallThis();
return 0;
}
void set_data(intptr_t x) {
@ -126,12 +138,14 @@ class NativeMovConstReg : public NativeInstruction {
inline NativeMovConstReg* nativeMovConstReg_at(address address) {
ShouldNotCallThis();
return NULL;
}
class NativeMovRegMem : public NativeInstruction {
public:
int offset() const {
ShouldNotCallThis();
return 0;
}
void set_offset(intptr_t x) {
@ -145,6 +159,7 @@ class NativeMovRegMem : public NativeInstruction {
inline NativeMovRegMem* nativeMovRegMem_at(address address) {
ShouldNotCallThis();
return NULL;
}
class NativeJump : public NativeInstruction {
@ -155,6 +170,7 @@ class NativeJump : public NativeInstruction {
address jump_destination() const {
ShouldNotCallThis();
return NULL;
}
void set_jump_destination(address dest) {
@ -172,12 +188,14 @@ class NativeJump : public NativeInstruction {
inline NativeJump* nativeJump_at(address address) {
ShouldNotCallThis();
return NULL;
}
class NativeGeneralJump : public NativeInstruction {
public:
address jump_destination() const {
ShouldNotCallThis();
return NULL;
}
static void insert_unconditional(address code_pos, address entry) {
@ -191,6 +209,7 @@ class NativeGeneralJump : public NativeInstruction {
inline NativeGeneralJump* nativeGeneralJump_at(address address) {
ShouldNotCallThis();
return NULL;
}
#endif // CPU_ZERO_VM_NATIVEINST_ZERO_HPP

View File

@ -32,8 +32,10 @@ const int ConcreteRegisterImpl::max_fpr =
const char* RegisterImpl::name() const {
ShouldNotCallThis();
return NULL;
}
const char* FloatRegisterImpl::name() const {
ShouldNotCallThis();
return NULL;
}

View File

@ -37,6 +37,7 @@ void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) {
address Relocation::pd_call_destination(address orig_addr) {
ShouldNotCallThis();
return NULL;
}
void Relocation::pd_set_call_destination(address x) {
@ -45,6 +46,7 @@ void Relocation::pd_set_call_destination(address x) {
address Relocation::pd_get_address_from_code() {
ShouldNotCallThis();
return NULL;
}
address* Relocation::pd_address_in_code() {

View File

@ -89,6 +89,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
ret_type);
#else
ShouldNotCallThis();
return NULL;
#endif // SHARK
}
@ -99,6 +100,7 @@ int Deoptimization::last_frame_adjust(int callee_parameters,
uint SharedRuntime::out_preserve_stack_slots() {
ShouldNotCallThis();
return 0;
}
JRT_LEAF(void, zero_stub())
@ -135,4 +137,5 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
VMRegPair *regs,
int total_args_passed) {
ShouldNotCallThis();
return 0;
}

View File

@ -39,16 +39,20 @@
VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
ShouldNotCallThis();
return NULL;
}
VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
ShouldNotCallThis();
return NULL;
}
int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
ShouldNotCallThis();
return 0;
}
int VtableStub::pd_code_alignment() {
ShouldNotCallThis();
return 0;
}

View File

@ -642,13 +642,14 @@ objc_registerThreadWithCollector_t objc_registerThreadWithCollectorFunction = NU
#endif
#ifdef __APPLE__
static uint64_t locate_unique_thread_id() {
static uint64_t locate_unique_thread_id(mach_port_t mach_thread_port) {
// Additional thread_id used to correlate threads in SA
thread_identifier_info_data_t m_ident_info;
mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
thread_info(::mach_thread_self(), THREAD_IDENTIFIER_INFO,
thread_info(mach_thread_port, THREAD_IDENTIFIER_INFO,
(thread_info_t) &m_ident_info, &count);
return m_ident_info.thread_id;
}
#endif
@ -679,9 +680,14 @@ static void *java_start(Thread *thread) {
}
#ifdef __APPLE__
// thread_id is mach thread on macos
osthread->set_thread_id(::mach_thread_self());
osthread->set_unique_thread_id(locate_unique_thread_id());
// thread_id is mach thread on macos, which pthreads graciously caches and provides for us
mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self());
guarantee(thread_id != 0, "thread id missing from pthreads");
osthread->set_thread_id(thread_id);
uint64_t unique_thread_id = locate_unique_thread_id(thread_id);
guarantee(unique_thread_id != 0, "unique thread id was not found");
osthread->set_unique_thread_id(unique_thread_id);
#else
// thread_id is pthread_id on BSD
osthread->set_thread_id(::pthread_self());
@ -843,8 +849,14 @@ bool os::create_attached_thread(JavaThread* thread) {
// Store pthread info into the OSThread
#ifdef __APPLE__
osthread->set_thread_id(::mach_thread_self());
osthread->set_unique_thread_id(locate_unique_thread_id());
// thread_id is mach thread on macos, which pthreads graciously caches and provides for us
mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self());
guarantee(thread_id != 0, "just checking");
osthread->set_thread_id(thread_id);
uint64_t unique_thread_id = locate_unique_thread_id(thread_id);
guarantee(unique_thread_id != 0, "just checking");
osthread->set_unique_thread_id(unique_thread_id);
#else
osthread->set_thread_id(::pthread_self());
#endif
@ -1115,7 +1127,7 @@ size_t os::lasterror(char *buf, size_t len) {
intx os::current_thread_id() {
#ifdef __APPLE__
return (intx)::mach_thread_self();
return (intx)::pthread_mach_thread_np(::pthread_self());
#else
return (intx)::pthread_self();
#endif
@ -2313,7 +2325,9 @@ void os::large_page_init() {
}
char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) {
char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) {
fatal("This code is not used or maintained.");
// "exec" is passed in but not used. Creating the shared image for
// the code cache doesn't have an SHM_X executable permission to check.
assert(UseLargePages && UseSHM, "only for SHM large pages");
@ -3275,11 +3289,15 @@ void os::Bsd::install_signal_handlers() {
// and if UserSignalHandler is installed all bets are off
if (CheckJNICalls) {
if (libjsig_is_loaded) {
tty->print_cr("Info: libjsig is activated, all active signal checking is disabled");
if (PrintJNIResolving) {
tty->print_cr("Info: libjsig is activated, all active signal checking is disabled");
}
check_signals = false;
}
if (AllowUserSignalHandlers) {
tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled");
if (PrintJNIResolving) {
tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled");
}
check_signals = false;
}
}
@ -4736,3 +4754,8 @@ int os::get_core_path(char* buffer, size_t bufferSize) {
return n;
}
#ifndef PRODUCT
void TestReserveMemorySpecial_test() {
// No tests available for this platform
}
#endif

View File

@ -40,6 +40,9 @@
product(bool, UseHugeTLBFS, false, \
"Use MAP_HUGETLB for large pages") \
\
product(bool, UseTransparentHugePages, false, \
"Use MADV_HUGEPAGE for large pages") \
\
product(bool, LoadExecStackDllInVMThread, true, \
"Load DLLs with executable-stack attribute in the VM Thread") \
\

View File

@ -2720,36 +2720,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec,
int os::Linux::commit_memory_impl(char* addr, size_t size,
size_t alignment_hint, bool exec) {
int err;
if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) {
int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
uintptr_t res =
(uintptr_t) ::mmap(addr, size, prot,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_HUGETLB,
-1, 0);
if (res != (uintptr_t) MAP_FAILED) {
if (UseNUMAInterleaving) {
numa_make_global(addr, size);
}
return 0;
}
err = errno; // save errno from mmap() call above
if (!recoverable_mmap_error(err)) {
// However, it is not clear that this loss of our reserved mapping
// happens with large pages on Linux or that we cannot recover
// from the loss. For now, we just issue a warning and we don't
// call vm_exit_out_of_memory(). This issue is being tracked by
// JBS-8007074.
warn_fail_commit_memory(addr, size, alignment_hint, exec, err);
// vm_exit_out_of_memory(size, OOM_MMAP_ERROR,
// "committing reserved memory.");
}
// Fall through and try to use small pages
}
err = os::Linux::commit_memory_impl(addr, size, exec);
int err = os::Linux::commit_memory_impl(addr, size, exec);
if (err == 0) {
realign_memory(addr, size, alignment_hint);
}
@ -2774,7 +2745,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size,
}
void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) {
if (UseTransparentHugePages && alignment_hint > (size_t)vm_page_size()) {
// We don't check the return value: madvise(MADV_HUGEPAGE) may not
// be supported or the memory may already be backed by huge pages.
::madvise(addr, bytes, MADV_HUGEPAGE);
@ -2787,7 +2758,7 @@ void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) {
// uncommitted at all. We don't do anything in this case to avoid creating a segment with
// small pages on top of the SHM segment. This method always works for small pages, so we
// allow that in any case.
if (alignment_hint <= (size_t)os::vm_page_size() || !UseSHM) {
if (alignment_hint <= (size_t)os::vm_page_size() || can_commit_large_page_memory()) {
commit_memory(addr, bytes, alignment_hint, !ExecMem);
}
}
@ -3157,11 +3128,31 @@ bool os::unguard_memory(char* addr, size_t size) {
return linux_mprotect(addr, size, PROT_READ|PROT_WRITE);
}
bool os::Linux::transparent_huge_pages_sanity_check(bool warn, size_t page_size) {
bool result = false;
void *p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE,
-1, 0);
if (p != MAP_FAILED) {
void *aligned_p = align_ptr_up(p, page_size);
result = madvise(aligned_p, page_size, MADV_HUGEPAGE) == 0;
munmap(p, page_size * 2);
}
if (warn && !result) {
warning("TransparentHugePages is not supported by the operating system.");
}
return result;
}
bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) {
bool result = false;
void *p = mmap (NULL, page_size, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB,
-1, 0);
void *p = mmap(NULL, page_size, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB,
-1, 0);
if (p != MAP_FAILED) {
// We don't know if this really is a huge page or not.
@ -3182,12 +3173,10 @@ bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) {
}
fclose(fp);
}
munmap (p, page_size);
if (result)
return true;
munmap(p, page_size);
}
if (warn) {
if (warn && !result) {
warning("HugeTLBFS is not supported by the operating system.");
}
@ -3235,82 +3224,114 @@ static void set_coredump_filter(void) {
static size_t _large_page_size = 0;
void os::large_page_init() {
if (!UseLargePages) {
UseHugeTLBFS = false;
UseSHM = false;
return;
}
size_t os::Linux::find_large_page_size() {
size_t large_page_size = 0;
if (FLAG_IS_DEFAULT(UseHugeTLBFS) && FLAG_IS_DEFAULT(UseSHM)) {
// If UseLargePages is specified on the command line try both methods,
// if it's default, then try only HugeTLBFS.
if (FLAG_IS_DEFAULT(UseLargePages)) {
UseHugeTLBFS = true;
} else {
UseHugeTLBFS = UseSHM = true;
}
}
if (LargePageSizeInBytes) {
_large_page_size = LargePageSizeInBytes;
} else {
// large_page_size on Linux is used to round up heap size. x86 uses either
// 2M or 4M page, depending on whether PAE (Physical Address Extensions)
// mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
// page as large as 256M.
//
// Here we try to figure out page size by parsing /proc/meminfo and looking
// for a line with the following format:
// Hugepagesize: 2048 kB
//
// If we can't determine the value (e.g. /proc is not mounted, or the text
// format has been changed), we'll use the largest page size supported by
// the processor.
// large_page_size on Linux is used to round up heap size. x86 uses either
// 2M or 4M page, depending on whether PAE (Physical Address Extensions)
// mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
// page as large as 256M.
//
// Here we try to figure out page size by parsing /proc/meminfo and looking
// for a line with the following format:
// Hugepagesize: 2048 kB
//
// If we can't determine the value (e.g. /proc is not mounted, or the text
// format has been changed), we'll use the largest page size supported by
// the processor.
#ifndef ZERO
_large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M)
ARM_ONLY(2 * M) PPC_ONLY(4 * M);
large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M)
ARM_ONLY(2 * M) PPC_ONLY(4 * M);
#endif // ZERO
FILE *fp = fopen("/proc/meminfo", "r");
if (fp) {
while (!feof(fp)) {
int x = 0;
char buf[16];
if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
_large_page_size = x * K;
break;
}
} else {
// skip to next line
for (;;) {
int ch = fgetc(fp);
if (ch == EOF || ch == (int)'\n') break;
}
FILE *fp = fopen("/proc/meminfo", "r");
if (fp) {
while (!feof(fp)) {
int x = 0;
char buf[16];
if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
large_page_size = x * K;
break;
}
} else {
// skip to next line
for (;;) {
int ch = fgetc(fp);
if (ch == EOF || ch == (int)'\n') break;
}
}
fclose(fp);
}
fclose(fp);
}
// print a warning if any large page related flag is specified on command line
bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS);
if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != large_page_size) {
warning("Setting LargePageSizeInBytes has no effect on this OS. Large page size is "
SIZE_FORMAT "%s.", byte_size_in_proper_unit(large_page_size),
proper_unit_for_byte_size(large_page_size));
}
return large_page_size;
}
size_t os::Linux::setup_large_page_size() {
_large_page_size = Linux::find_large_page_size();
const size_t default_page_size = (size_t)Linux::page_size();
if (_large_page_size > default_page_size) {
_page_sizes[0] = _large_page_size;
_page_sizes[1] = default_page_size;
_page_sizes[2] = 0;
}
UseHugeTLBFS = UseHugeTLBFS &&
Linux::hugetlbfs_sanity_check(warn_on_failure, _large_page_size);
if (UseHugeTLBFS)
return _large_page_size;
}
bool os::Linux::setup_large_page_type(size_t page_size) {
if (FLAG_IS_DEFAULT(UseHugeTLBFS) &&
FLAG_IS_DEFAULT(UseSHM) &&
FLAG_IS_DEFAULT(UseTransparentHugePages)) {
// If UseLargePages is specified on the command line try all methods,
// if it's default, then try only UseTransparentHugePages.
if (FLAG_IS_DEFAULT(UseLargePages)) {
UseTransparentHugePages = true;
} else {
UseHugeTLBFS = UseTransparentHugePages = UseSHM = true;
}
}
if (UseTransparentHugePages) {
bool warn_on_failure = !FLAG_IS_DEFAULT(UseTransparentHugePages);
if (transparent_huge_pages_sanity_check(warn_on_failure, page_size)) {
UseHugeTLBFS = false;
UseSHM = false;
return true;
}
UseTransparentHugePages = false;
}
if (UseHugeTLBFS) {
bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS);
if (hugetlbfs_sanity_check(warn_on_failure, page_size)) {
UseSHM = false;
return true;
}
UseHugeTLBFS = false;
}
return UseSHM;
}
void os::large_page_init() {
if (!UseLargePages) {
UseHugeTLBFS = false;
UseTransparentHugePages = false;
UseSHM = false;
return;
}
UseLargePages = UseHugeTLBFS || UseSHM;
size_t large_page_size = Linux::setup_large_page_size();
UseLargePages = Linux::setup_large_page_type(large_page_size);
set_coredump_filter();
}
@ -3319,16 +3340,22 @@ void os::large_page_init() {
#define SHM_HUGETLB 04000
#endif
char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) {
char* os::Linux::reserve_memory_special_shm(size_t bytes, size_t alignment, char* req_addr, bool exec) {
// "exec" is passed in but not used. Creating the shared image for
// the code cache doesn't have an SHM_X executable permission to check.
assert(UseLargePages && UseSHM, "only for SHM large pages");
assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address");
if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) {
return NULL; // Fallback to small pages.
}
key_t key = IPC_PRIVATE;
char *addr;
bool warn_on_failure = UseLargePages &&
(!FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(UseSHM) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes)
);
char msg[128];
@ -3376,42 +3403,219 @@ char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) {
return NULL;
}
if ((addr != NULL) && UseNUMAInterleaving) {
numa_make_global(addr, bytes);
return addr;
}
static void warn_on_large_pages_failure(char* req_addr, size_t bytes, int error) {
assert(error == ENOMEM, "Only expect to fail if no memory is available");
bool warn_on_failure = UseLargePages &&
(!FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(UseHugeTLBFS) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes));
if (warn_on_failure) {
char msg[128];
jio_snprintf(msg, sizeof(msg), "Failed to reserve large pages memory req_addr: "
PTR_FORMAT " bytes: " SIZE_FORMAT " (errno = %d).", req_addr, bytes, error);
warning(msg);
}
}
char* os::Linux::reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec) {
assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages");
assert(is_size_aligned(bytes, os::large_page_size()), "Unaligned size");
assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address");
int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
char* addr = (char*)::mmap(req_addr, bytes, prot,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB,
-1, 0);
if (addr == MAP_FAILED) {
warn_on_large_pages_failure(req_addr, bytes, errno);
return NULL;
}
// The memory is committed
MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC);
assert(is_ptr_aligned(addr, os::large_page_size()), "Must be");
return addr;
}
char* os::Linux::reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec) {
size_t large_page_size = os::large_page_size();
assert(bytes >= large_page_size, "Shouldn't allocate large pages for small sizes");
// Allocate small pages.
char* start;
if (req_addr != NULL) {
assert(is_ptr_aligned(req_addr, alignment), "Must be");
assert(is_size_aligned(bytes, alignment), "Must be");
start = os::reserve_memory(bytes, req_addr);
assert(start == NULL || start == req_addr, "Must be");
} else {
start = os::reserve_memory_aligned(bytes, alignment);
}
if (start == NULL) {
return NULL;
}
assert(is_ptr_aligned(start, alignment), "Must be");
// os::reserve_memory_special will record this memory area.
// Need to release it here to prevent overlapping reservations.
MemTracker::record_virtual_memory_release((address)start, bytes);
char* end = start + bytes;
// Find the regions of the allocated chunk that can be promoted to large pages.
char* lp_start = (char*)align_ptr_up(start, large_page_size);
char* lp_end = (char*)align_ptr_down(end, large_page_size);
size_t lp_bytes = lp_end - lp_start;
assert(is_size_aligned(lp_bytes, large_page_size), "Must be");
if (lp_bytes == 0) {
// The mapped region doesn't even span the start and the end of a large page.
// Fall back to allocate a non-special area.
::munmap(start, end - start);
return NULL;
}
int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
void* result;
if (start != lp_start) {
result = ::mmap(start, lp_start - start, prot,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
-1, 0);
if (result == MAP_FAILED) {
::munmap(lp_start, end - lp_start);
return NULL;
}
}
result = ::mmap(lp_start, lp_bytes, prot,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_HUGETLB,
-1, 0);
if (result == MAP_FAILED) {
warn_on_large_pages_failure(req_addr, bytes, errno);
// If the mmap above fails, the large pages region will be unmapped and we
// have regions before and after with small pages. Release these regions.
//
// | mapped | unmapped | mapped |
// ^ ^ ^ ^
// start lp_start lp_end end
//
::munmap(start, lp_start - start);
::munmap(lp_end, end - lp_end);
return NULL;
}
if (lp_end != end) {
result = ::mmap(lp_end, end - lp_end, prot,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED,
-1, 0);
if (result == MAP_FAILED) {
::munmap(start, lp_end - start);
return NULL;
}
}
return start;
}
char* os::Linux::reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, char* req_addr, bool exec) {
assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages");
assert(is_ptr_aligned(req_addr, alignment), "Must be");
assert(is_power_of_2(alignment), "Must be");
assert(is_power_of_2(os::large_page_size()), "Must be");
assert(bytes >= os::large_page_size(), "Shouldn't allocate large pages for small sizes");
if (is_size_aligned(bytes, os::large_page_size()) && alignment <= os::large_page_size()) {
return reserve_memory_special_huge_tlbfs_only(bytes, req_addr, exec);
} else {
return reserve_memory_special_huge_tlbfs_mixed(bytes, alignment, req_addr, exec);
}
}
char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) {
assert(UseLargePages, "only for large pages");
char* addr;
if (UseSHM) {
addr = os::Linux::reserve_memory_special_shm(bytes, alignment, req_addr, exec);
} else {
assert(UseHugeTLBFS, "must be");
addr = os::Linux::reserve_memory_special_huge_tlbfs(bytes, alignment, req_addr, exec);
}
if (addr != NULL) {
if (UseNUMAInterleaving) {
numa_make_global(addr, bytes);
}
// The memory is committed
MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC);
}
return addr;
}
bool os::Linux::release_memory_special_shm(char* base, size_t bytes) {
// detaching the SHM segment will also delete it, see reserve_memory_special_shm()
return shmdt(base) == 0;
}
bool os::Linux::release_memory_special_huge_tlbfs(char* base, size_t bytes) {
return pd_release_memory(base, bytes);
}
bool os::release_memory_special(char* base, size_t bytes) {
assert(UseLargePages, "only for large pages");
MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
// detaching the SHM segment will also delete it, see reserve_memory_special()
int rslt = shmdt(base);
if (rslt == 0) {
bool res;
if (UseSHM) {
res = os::Linux::release_memory_special_shm(base, bytes);
} else {
assert(UseHugeTLBFS, "must be");
res = os::Linux::release_memory_special_huge_tlbfs(base, bytes);
}
if (res) {
tkr.record((address)base, bytes);
return true;
} else {
tkr.discard();
return false;
}
return res;
}
size_t os::large_page_size() {
return _large_page_size;
}
// HugeTLBFS allows application to commit large page memory on demand;
// with SysV SHM the entire memory region must be allocated as shared
// With SysV SHM the entire memory region must be allocated as shared
// memory.
// HugeTLBFS allows application to commit large page memory on demand.
// However, when committing memory with HugeTLBFS fails, the region
// that was supposed to be committed will lose the old reservation
// and allow other threads to steal that memory region. Because of this
// behavior we can't commit HugeTLBFS memory.
bool os::can_commit_large_page_memory() {
return UseHugeTLBFS;
return UseTransparentHugePages;
}
bool os::can_execute_large_page_memory() {
return UseHugeTLBFS;
return UseTransparentHugePages || UseHugeTLBFS;
}
// Reserve memory at an arbitrary address, only if that area is
@ -4563,21 +4767,23 @@ jint os::init_2(void)
UseNUMA = false;
}
}
// With SHM large pages we cannot uncommit a page, so there's not way
// With SHM and HugeTLBFS large pages we cannot uncommit a page, so there's no way
// we can make the adaptive lgrp chunk resizing work. If the user specified
// both UseNUMA and UseLargePages (or UseSHM) on the command line - warn and
// both UseNUMA and UseLargePages (or UseSHM/UseHugeTLBFS) on the command line - warn and
// disable adaptive resizing.
if (UseNUMA && UseLargePages && UseSHM) {
if (!FLAG_IS_DEFAULT(UseNUMA)) {
if (FLAG_IS_DEFAULT(UseLargePages) && FLAG_IS_DEFAULT(UseSHM)) {
if (UseNUMA && UseLargePages && !can_commit_large_page_memory()) {
if (FLAG_IS_DEFAULT(UseNUMA)) {
UseNUMA = false;
} else {
if (FLAG_IS_DEFAULT(UseLargePages) &&
FLAG_IS_DEFAULT(UseSHM) &&
FLAG_IS_DEFAULT(UseHugeTLBFS)) {
UseLargePages = false;
} else {
warning("UseNUMA is not fully compatible with SHM large pages, disabling adaptive resizing");
warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing");
UseAdaptiveSizePolicy = false;
UseAdaptiveNUMAChunkSizing = false;
}
} else {
UseNUMA = false;
}
}
if (!UseNUMA && ForceNUMA) {
@ -5848,3 +6054,149 @@ void MemNotifyThread::start() {
}
#endif // JAVASE_EMBEDDED
/////////////// Unit tests ///////////////
#ifndef PRODUCT
#define test_log(...) \
do {\
if (VerboseInternalVMTests) { \
tty->print_cr(__VA_ARGS__); \
tty->flush(); \
}\
} while (false)
class TestReserveMemorySpecial : AllStatic {
public:
static void small_page_write(void* addr, size_t size) {
size_t page_size = os::vm_page_size();
char* end = (char*)addr + size;
for (char* p = (char*)addr; p < end; p += page_size) {
*p = 1;
}
}
static void test_reserve_memory_special_huge_tlbfs_only(size_t size) {
if (!UseHugeTLBFS) {
return;
}
test_log("test_reserve_memory_special_huge_tlbfs_only(" SIZE_FORMAT ")", size);
char* addr = os::Linux::reserve_memory_special_huge_tlbfs_only(size, NULL, false);
if (addr != NULL) {
small_page_write(addr, size);
os::Linux::release_memory_special_huge_tlbfs(addr, size);
}
}
static void test_reserve_memory_special_huge_tlbfs_only() {
if (!UseHugeTLBFS) {
return;
}
size_t lp = os::large_page_size();
for (size_t size = lp; size <= lp * 10; size += lp) {
test_reserve_memory_special_huge_tlbfs_only(size);
}
}
static void test_reserve_memory_special_huge_tlbfs_mixed(size_t size, size_t alignment) {
if (!UseHugeTLBFS) {
return;
}
test_log("test_reserve_memory_special_huge_tlbfs_mixed(" SIZE_FORMAT ", " SIZE_FORMAT ")",
size, alignment);
assert(size >= os::large_page_size(), "Incorrect input to test");
char* addr = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, NULL, false);
if (addr != NULL) {
small_page_write(addr, size);
os::Linux::release_memory_special_huge_tlbfs(addr, size);
}
}
static void test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(size_t size) {
size_t lp = os::large_page_size();
size_t ag = os::vm_allocation_granularity();
for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) {
test_reserve_memory_special_huge_tlbfs_mixed(size, alignment);
}
}
static void test_reserve_memory_special_huge_tlbfs_mixed() {
size_t lp = os::large_page_size();
size_t ag = os::vm_allocation_granularity();
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + ag);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + lp / 2);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + ag);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 - ag);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + lp / 2);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10);
test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10 + lp / 2);
}
static void test_reserve_memory_special_huge_tlbfs() {
if (!UseHugeTLBFS) {
return;
}
test_reserve_memory_special_huge_tlbfs_only();
test_reserve_memory_special_huge_tlbfs_mixed();
}
static void test_reserve_memory_special_shm(size_t size, size_t alignment) {
if (!UseSHM) {
return;
}
test_log("test_reserve_memory_special_shm(" SIZE_FORMAT ", " SIZE_FORMAT ")", size, alignment);
char* addr = os::Linux::reserve_memory_special_shm(size, alignment, NULL, false);
if (addr != NULL) {
assert(is_ptr_aligned(addr, alignment), "Check");
assert(is_ptr_aligned(addr, os::large_page_size()), "Check");
small_page_write(addr, size);
os::Linux::release_memory_special_shm(addr, size);
}
}
static void test_reserve_memory_special_shm() {
size_t lp = os::large_page_size();
size_t ag = os::vm_allocation_granularity();
for (size_t size = ag; size < lp * 3; size += ag) {
for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) {
test_reserve_memory_special_shm(size, alignment);
}
}
}
static void test() {
test_reserve_memory_special_huge_tlbfs();
test_reserve_memory_special_shm();
}
};
void TestReserveMemorySpecial_test() {
TestReserveMemorySpecial::test();
}
#endif

View File

@ -32,6 +32,7 @@ typedef int (*pthread_getattr_func_type) (pthread_t, pthread_attr_t *);
class Linux {
friend class os;
friend class TestReserveMemorySpecial;
// For signal-chaining
#define MAXSIGNUM 32
@ -92,8 +93,21 @@ class Linux {
static void rebuild_cpu_to_node_map();
static GrowableArray<int>* cpu_to_node() { return _cpu_to_node; }
static size_t find_large_page_size();
static size_t setup_large_page_size();
static bool setup_large_page_type(size_t page_size);
static bool transparent_huge_pages_sanity_check(bool warn, size_t pages_size);
static bool hugetlbfs_sanity_check(bool warn, size_t page_size);
static char* reserve_memory_special_shm(size_t bytes, size_t alignment, char* req_addr, bool exec);
static char* reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, char* req_addr, bool exec);
static char* reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec);
static char* reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec);
static bool release_memory_special_shm(char* base, size_t bytes);
static bool release_memory_special_huge_tlbfs(char* base, size_t bytes);
static void print_full_memory_info(outputStream* st);
static void print_distro_info(outputStream* st);
static void print_libversion_info(outputStream* st);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -260,6 +260,55 @@ FILE* os::open(int fd, const char* mode) {
return ::fdopen(fd, mode);
}
void* os::get_default_process_handle() {
return (void*)::dlopen(NULL, RTLD_LAZY);
}
// Builds a platform dependent Agent_OnLoad_<lib_name> function name
// which is used to find statically linked in agents.
// Parameters:
// sym_name: Symbol in library we are looking for
// lib_name: Name of library to look in, NULL for shared libs.
// is_absolute_path == true if lib_name is absolute path to agent
// such as "/a/b/libL.so"
// == false if only the base name of the library is passed in
// such as "L"
char* os::build_agent_function_name(const char *sym_name, const char *lib_name,
bool is_absolute_path) {
char *agent_entry_name;
size_t len;
size_t name_len;
size_t prefix_len = strlen(JNI_LIB_PREFIX);
size_t suffix_len = strlen(JNI_LIB_SUFFIX);
const char *start;
if (lib_name != NULL) {
len = name_len = strlen(lib_name);
if (is_absolute_path) {
// Need to strip path, prefix and suffix
if ((start = strrchr(lib_name, *os::file_separator())) != NULL) {
lib_name = ++start;
}
if (len <= (prefix_len + suffix_len)) {
return NULL;
}
lib_name += prefix_len;
name_len = strlen(lib_name) - suffix_len;
}
}
len = (lib_name != NULL ? name_len : 0) + strlen(sym_name) + 2;
agent_entry_name = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len, mtThread);
if (agent_entry_name == NULL) {
return NULL;
}
strcpy(agent_entry_name, sym_name);
if (lib_name != NULL) {
strcat(agent_entry_name, "_");
strncat(agent_entry_name, lib_name, name_len);
}
return agent_entry_name;
}
os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() {
assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread");
}

View File

@ -3385,7 +3385,7 @@ bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) {
return true;
}
char* os::reserve_memory_special(size_t size, char* addr, bool exec) {
char* os::reserve_memory_special(size_t size, size_t alignment, char* addr, bool exec) {
fatal("os::reserve_memory_special should not be called on Solaris.");
return NULL;
}
@ -6601,3 +6601,9 @@ int os::get_core_path(char* buffer, size_t bufferSize) {
return strlen(buffer);
}
#ifndef PRODUCT
void TestReserveMemorySpecial_test() {
// No tests available for this platform
}
#endif

View File

@ -3156,7 +3156,12 @@ bool os::can_execute_large_page_memory() {
return true;
}
char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) {
char* os::reserve_memory_special(size_t bytes, size_t alignment, char* addr, bool exec) {
assert(UseLargePages, "only for large pages");
if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) {
return NULL; // Fallback to small pages.
}
const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
@ -5394,6 +5399,75 @@ inline BOOL os::Advapi32Dll::AdvapiAvailable() {
return true;
}
void* os::get_default_process_handle() {
return (void*)GetModuleHandle(NULL);
}
// Builds a platform dependent Agent_OnLoad_<lib_name> function name
// which is used to find statically linked in agents.
// Additionally for windows, takes into account __stdcall names.
// Parameters:
// sym_name: Symbol in library we are looking for
// lib_name: Name of library to look in, NULL for shared libs.
// is_absolute_path == true if lib_name is absolute path to agent
// such as "C:/a/b/L.dll"
// == false if only the base name of the library is passed in
// such as "L"
char* os::build_agent_function_name(const char *sym_name, const char *lib_name,
bool is_absolute_path) {
char *agent_entry_name;
size_t len;
size_t name_len;
size_t prefix_len = strlen(JNI_LIB_PREFIX);
size_t suffix_len = strlen(JNI_LIB_SUFFIX);
const char *start;
if (lib_name != NULL) {
len = name_len = strlen(lib_name);
if (is_absolute_path) {
// Need to strip path, prefix and suffix
if ((start = strrchr(lib_name, *os::file_separator())) != NULL) {
lib_name = ++start;
} else {
// Need to check for C:
if ((start = strchr(lib_name, ':')) != NULL) {
lib_name = ++start;
}
}
if (len <= (prefix_len + suffix_len)) {
return NULL;
}
lib_name += prefix_len;
name_len = strlen(lib_name) - suffix_len;
}
}
len = (lib_name != NULL ? name_len : 0) + strlen(sym_name) + 2;
agent_entry_name = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len, mtThread);
if (agent_entry_name == NULL) {
return NULL;
}
if (lib_name != NULL) {
const char *p = strrchr(sym_name, '@');
if (p != NULL && p != sym_name) {
// sym_name == _Agent_OnLoad@XX
strncpy(agent_entry_name, sym_name, (p - sym_name));
agent_entry_name[(p-sym_name)] = '\0';
// agent_entry_name == _Agent_OnLoad
strcat(agent_entry_name, "_");
strncat(agent_entry_name, lib_name, name_len);
strcat(agent_entry_name, p);
// agent_entry_name == _Agent_OnLoad_lib_name@XX
} else {
strcpy(agent_entry_name, sym_name);
strcat(agent_entry_name, "_");
strncat(agent_entry_name, lib_name, name_len);
}
} else {
strcpy(agent_entry_name, sym_name);
}
return agent_entry_name;
}
#else
// Kernel32 API
typedef BOOL (WINAPI* SwitchToThread_Fn)(void);
@ -5638,3 +5712,9 @@ BOOL os::Advapi32Dll::AdvapiAvailable() {
}
#endif
#ifndef PRODUCT
void TestReserveMemorySpecial_test() {
// No tests available for this platform
}
#endif

View File

@ -190,7 +190,7 @@ inline void OrderAccess::release_store_fence(volatile juint* p, juint v)
inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { release_store_fence((volatile jlong*)p, (jlong)v); }
inline void OrderAccess::release_store_fence(volatile jfloat* p, jfloat v) { *p = v; fence(); }
inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { release_store_fence((volatile jlong*)p, jdouble_cast(v)); }
inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { release_store_fence((volatile jlong*)p, jlong_cast(v)); }
inline void OrderAccess::release_store_ptr_fence(volatile intptr_t* p, intptr_t v) {
#ifdef AMD64

View File

@ -715,6 +715,7 @@ JVM_handle_bsd_signal(int sig,
err.report_and_die();
ShouldNotReachHere();
return false;
}
// From solaris_i486.s ported to bsd_i486.s

View File

@ -66,6 +66,7 @@ address os::current_stack_pointer() {
frame os::get_sender_for_C_frame(frame* fr) {
ShouldNotCallThis();
return frame();
}
frame os::current_frame() {
@ -103,16 +104,19 @@ void os::initialize_thread(Thread* thr) {
address os::Bsd::ucontext_get_pc(ucontext_t* uc) {
ShouldNotCallThis();
return NULL;
}
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
intptr_t** ret_sp,
intptr_t** ret_fp) {
ShouldNotCallThis();
return ExtendedPC();
}
frame os::fetch_frame_from_context(void* ucVoid) {
ShouldNotCallThis();
return frame();
}
extern "C" JNIEXPORT int
@ -240,6 +244,7 @@ JVM_handle_bsd_signal(int sig,
sprintf(buf, fmt, sig, info->si_addr);
fatal(buf);
return false;
}
void os::Bsd::init_thread_fpu_state(void) {
@ -373,17 +378,7 @@ void os::print_register_info(outputStream *st, void *context) {
extern "C" {
int SpinPause() {
}
int SafeFetch32(int *adr, int errValue) {
int value = errValue;
value = *adr;
return value;
}
intptr_t SafeFetchN(intptr_t *adr, intptr_t errValue) {
intptr_t value = errValue;
value = *adr;
return value;
return 1;
}
void _Copy_conjoint_jshorts_atomic(jshort* from, jshort* to, size_t count) {

View File

@ -110,6 +110,7 @@
void* ucontext,
bool isInJava) {
ShouldNotCallThis();
return false;
}
// These routines are only used on cpu architectures that

View File

@ -915,16 +915,6 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
// Return to the now deoptimized frame.
}
// If we are patching in a non-perm oop, make sure the nmethod
// is on the right list.
if (ScavengeRootsInCode && mirror.not_null() && mirror()->is_scavengable()) {
MutexLockerEx ml_code (CodeCache_lock, Mutex::_no_safepoint_check_flag);
nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
guarantee(nm != NULL, "only nmethods can contain non-perm oops");
if (!nm->on_scavenge_root_list())
CodeCache::add_scavenge_root_nmethod(nm);
}
// Now copy code back
{
@ -1125,6 +1115,21 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
}
}
}
// If we are patching in a non-perm oop, make sure the nmethod
// is on the right list.
if (ScavengeRootsInCode && mirror.not_null() && mirror()->is_scavengable()) {
MutexLockerEx ml_code (CodeCache_lock, Mutex::_no_safepoint_check_flag);
nmethod* nm = CodeCache::find_nmethod(caller_frame.pc());
guarantee(nm != NULL, "only nmethods can contain non-perm oops");
if (!nm->on_scavenge_root_list()) {
CodeCache::add_scavenge_root_nmethod(nm);
}
// Since we've patched some oops in the nmethod,
// (re)register it with the heap.
Universe::heap()->register_nmethod(nm);
}
JRT_END
//

View File

@ -2590,7 +2590,7 @@ void ClassFileParser::parse_classfile_sourcefile_attribute(TRAPS) {
valid_symbol_at(sourcefile_index),
"Invalid SourceFile attribute at constant pool index %u in class file %s",
sourcefile_index, CHECK);
set_class_sourcefile(_cp->symbol_at(sourcefile_index));
set_class_sourcefile_index(sourcefile_index);
}
@ -2728,7 +2728,7 @@ void ClassFileParser::parse_classfile_signature_attribute(TRAPS) {
valid_symbol_at(signature_index),
"Invalid constant pool index %u in Signature attribute in class file %s",
signature_index, CHECK);
set_class_generic_signature(_cp->symbol_at(signature_index));
set_class_generic_signature_index(signature_index);
}
void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_byte_length, TRAPS) {
@ -2975,13 +2975,11 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio
void ClassFileParser::apply_parsed_class_attributes(instanceKlassHandle k) {
if (_synthetic_flag)
k->set_is_synthetic();
if (_sourcefile != NULL) {
_sourcefile->increment_refcount();
k->set_source_file_name(_sourcefile);
if (_sourcefile_index != 0) {
k->set_source_file_name_index(_sourcefile_index);
}
if (_generic_signature != NULL) {
_generic_signature->increment_refcount();
k->set_generic_signature(_generic_signature);
if (_generic_signature_index != 0) {
k->set_generic_signature_index(_generic_signature_index);
}
if (_sde_buffer != NULL) {
k->set_source_debug_extension(_sde_buffer, _sde_length);

View File

@ -62,8 +62,8 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
bool _synthetic_flag;
int _sde_length;
char* _sde_buffer;
Symbol* _sourcefile;
Symbol* _generic_signature;
u2 _sourcefile_index;
u2 _generic_signature_index;
// Metadata created before the instance klass is created. Must be deallocated
// if not transferred to the InstanceKlass upon successful class loading
@ -81,16 +81,16 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
Array<AnnotationArray*>* _fields_type_annotations;
InstanceKlass* _klass; // InstanceKlass once created.
void set_class_synthetic_flag(bool x) { _synthetic_flag = x; }
void set_class_sourcefile(Symbol* x) { _sourcefile = x; }
void set_class_generic_signature(Symbol* x) { _generic_signature = x; }
void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; }
void set_class_synthetic_flag(bool x) { _synthetic_flag = x; }
void set_class_sourcefile_index(u2 x) { _sourcefile_index = x; }
void set_class_generic_signature_index(u2 x) { _generic_signature_index = x; }
void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; }
void init_parsed_class_attributes(ClassLoaderData* loader_data) {
_loader_data = loader_data;
_synthetic_flag = false;
_sourcefile = NULL;
_generic_signature = NULL;
_sourcefile_index = 0;
_generic_signature_index = 0;
_sde_buffer = NULL;
_sde_length = 0;
// initialize the other flags too:

View File

@ -687,6 +687,7 @@ nmethod::nmethod(
code_buffer->copy_values_to(this);
if (ScavengeRootsInCode && detect_scavenge_root_oops()) {
CodeCache::add_scavenge_root_nmethod(this);
Universe::heap()->register_nmethod(this);
}
debug_only(verify_scavenge_root_oops());
CodeCache::commit(this);
@ -881,6 +882,7 @@ nmethod::nmethod(
dependencies->copy_to(this);
if (ScavengeRootsInCode && detect_scavenge_root_oops()) {
CodeCache::add_scavenge_root_nmethod(this);
Universe::heap()->register_nmethod(this);
}
debug_only(verify_scavenge_root_oops());
@ -1300,6 +1302,13 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
methodHandle the_method(method());
No_Safepoint_Verifier nsv;
// during patching, depending on the nmethod state we must notify the GC that
// code has been unloaded, unregistering it. We cannot do this right while
// holding the Patching_lock because we need to use the CodeCache_lock. This
// would be prone to deadlocks.
// This flag is used to remember whether we need to later lock and unregister.
bool nmethod_needs_unregister = false;
{
// invalidate osr nmethod before acquiring the patching lock since
// they both acquire leaf locks and we don't want a deadlock.
@ -1332,6 +1341,13 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
inc_decompile_count();
}
// If the state is becoming a zombie, signal to unregister the nmethod with
// the heap.
// This nmethod may have already been unloaded during a full GC.
if ((state == zombie) && !is_unloaded()) {
nmethod_needs_unregister = true;
}
// Change state
_state = state;
@ -1367,6 +1383,9 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
// safepoint can sneak in, otherwise the oops used by the
// dependency logic could have become stale.
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
if (nmethod_needs_unregister) {
Universe::heap()->unregister_nmethod(this);
}
flush_dependencies(NULL);
}
@ -1817,21 +1836,10 @@ void nmethod::metadata_do(void f(Metadata*)) {
if (_method != NULL) f(_method);
}
// This method is called twice during GC -- once while
// tracing the "active" nmethods on thread stacks during
// the (strong) marking phase, and then again when walking
// the code cache contents during the weak roots processing
// phase. The two uses are distinguished by means of the
// 'do_strong_roots_only' flag, which is true in the first
// case. We want to walk the weak roots in the nmethod
// only in the second case. The weak roots in the nmethod
// are the oops in the ExceptionCache and the InlineCache
// oops.
void nmethod::oops_do(OopClosure* f, bool do_strong_roots_only) {
void nmethod::oops_do(OopClosure* f, bool allow_zombie) {
// make sure the oops ready to receive visitors
assert(!is_zombie() && !is_unloaded(),
"should not call follow on zombie or unloaded nmethod");
assert(allow_zombie || !is_zombie(), "should not call follow on zombie nmethod");
assert(!is_unloaded(), "should not call follow on unloaded nmethod");
// If the method is not entrant or zombie then a JMP is plastered over the
// first few bytes. If an oop in the old code was there, that oop

View File

@ -566,7 +566,7 @@ public:
void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map,
OopClosure* f);
void oops_do(OopClosure* f) { oops_do(f, false); }
void oops_do(OopClosure* f, bool do_strong_roots_only);
void oops_do(OopClosure* f, bool allow_zombie);
bool detect_scavenge_root_oops();
void verify_scavenge_root_oops() PRODUCT_RETURN;

View File

@ -3460,7 +3460,9 @@ void ConcurrentMarkSweepGeneration::shrink_by(size_t bytes) {
void ConcurrentMarkSweepGeneration::shrink(size_t bytes) {
assert_locked_or_safepoint(Heap_lock);
size_t size = ReservedSpace::page_align_size_down(bytes);
if (size > 0) {
// Only shrink if a compaction was done so that all the free space
// in the generation is in a contiguous block at the end.
if (size > 0 && did_compact()) {
shrink_by(size);
}
}
@ -5478,40 +5480,42 @@ CMSParMarkTask::do_young_space_rescan(uint worker_id,
HandleMark hm;
SequentialSubTasksDone* pst = space->par_seq_tasks();
assert(pst->valid(), "Uninitialized use?");
uint nth_task = 0;
uint n_tasks = pst->n_tasks();
HeapWord *start, *end;
while (!pst->is_task_claimed(/* reference */ nth_task)) {
// We claimed task # nth_task; compute its boundaries.
if (chunk_top == 0) { // no samples were taken
assert(nth_task == 0 && n_tasks == 1, "Can have only 1 EdenSpace task");
start = space->bottom();
end = space->top();
} else if (nth_task == 0) {
start = space->bottom();
end = chunk_array[nth_task];
} else if (nth_task < (uint)chunk_top) {
assert(nth_task >= 1, "Control point invariant");
start = chunk_array[nth_task - 1];
end = chunk_array[nth_task];
} else {
assert(nth_task == (uint)chunk_top, "Control point invariant");
start = chunk_array[chunk_top - 1];
end = space->top();
if (n_tasks > 0) {
assert(pst->valid(), "Uninitialized use?");
HeapWord *start, *end;
while (!pst->is_task_claimed(/* reference */ nth_task)) {
// We claimed task # nth_task; compute its boundaries.
if (chunk_top == 0) { // no samples were taken
assert(nth_task == 0 && n_tasks == 1, "Can have only 1 EdenSpace task");
start = space->bottom();
end = space->top();
} else if (nth_task == 0) {
start = space->bottom();
end = chunk_array[nth_task];
} else if (nth_task < (uint)chunk_top) {
assert(nth_task >= 1, "Control point invariant");
start = chunk_array[nth_task - 1];
end = chunk_array[nth_task];
} else {
assert(nth_task == (uint)chunk_top, "Control point invariant");
start = chunk_array[chunk_top - 1];
end = space->top();
}
MemRegion mr(start, end);
// Verify that mr is in space
assert(mr.is_empty() || space->used_region().contains(mr),
"Should be in space");
// Verify that "start" is an object boundary
assert(mr.is_empty() || oop(mr.start())->is_oop(),
"Should be an oop");
space->par_oop_iterate(mr, cl);
}
MemRegion mr(start, end);
// Verify that mr is in space
assert(mr.is_empty() || space->used_region().contains(mr),
"Should be in space");
// Verify that "start" is an object boundary
assert(mr.is_empty() || oop(mr.start())->is_oop(),
"Should be an oop");
space->par_oop_iterate(mr, cl);
pst->all_tasks_completed();
}
pst->all_tasks_completed();
}
void
@ -5788,7 +5792,7 @@ initialize_sequential_subtasks_for_young_gen_rescan(int n_threads) {
DefNewGeneration* dng = (DefNewGeneration*)_young_gen;
// Eden space
{
if (!dng->eden()->is_empty()) {
SequentialSubTasksDone* pst = dng->eden()->par_seq_tasks();
assert(!pst->valid(), "Clobbering existing data?");
// Each valid entry in [0, _eden_chunk_index) represents a task.
@ -8694,9 +8698,10 @@ void SweepClosure::lookahead_and_flush(FreeChunk* fc, size_t chunk_size) {
assert(inFreeRange(), "Should only be called if currently in a free range.");
HeapWord* const eob = ((HeapWord*)fc) + chunk_size;
assert(_sp->used_region().contains(eob - 1),
err_msg("eob = " PTR_FORMAT " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")"
err_msg("eob = " PTR_FORMAT " eob-1 = " PTR_FORMAT " _limit = " PTR_FORMAT
" out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")"
" when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")",
_limit, _sp->bottom(), _sp->end(), fc, chunk_size));
eob, eob-1, _limit, _sp->bottom(), _sp->end(), fc, chunk_size));
if (eob >= _limit) {
assert(eob == _limit || fc->is_free(), "Only a free chunk should allow us to cross over the limit");
if (CMSTraceSweeper) {

View File

@ -4529,7 +4529,7 @@ G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name)
_total_prev_live_bytes(0), _total_next_live_bytes(0),
_hum_used_bytes(0), _hum_capacity_bytes(0),
_hum_prev_live_bytes(0), _hum_next_live_bytes(0),
_total_remset_bytes(0) {
_total_remset_bytes(0), _total_strong_code_roots_bytes(0) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
MemRegion g1_committed = g1h->g1_committed();
MemRegion g1_reserved = g1h->g1_reserved();
@ -4553,9 +4553,11 @@ G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name)
G1PPRL_BYTE_H_FORMAT
G1PPRL_BYTE_H_FORMAT
G1PPRL_DOUBLE_H_FORMAT
G1PPRL_BYTE_H_FORMAT
G1PPRL_BYTE_H_FORMAT,
"type", "address-range",
"used", "prev-live", "next-live", "gc-eff", "remset");
"used", "prev-live", "next-live", "gc-eff",
"remset", "code-roots");
_out->print_cr(G1PPRL_LINE_PREFIX
G1PPRL_TYPE_H_FORMAT
G1PPRL_ADDR_BASE_H_FORMAT
@ -4563,9 +4565,11 @@ G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name)
G1PPRL_BYTE_H_FORMAT
G1PPRL_BYTE_H_FORMAT
G1PPRL_DOUBLE_H_FORMAT
G1PPRL_BYTE_H_FORMAT
G1PPRL_BYTE_H_FORMAT,
"", "",
"(bytes)", "(bytes)", "(bytes)", "(bytes/ms)", "(bytes)");
"(bytes)", "(bytes)", "(bytes)", "(bytes/ms)",
"(bytes)", "(bytes)");
}
// It takes as a parameter a reference to one of the _hum_* fields, it
@ -4608,6 +4612,8 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) {
size_t next_live_bytes = r->next_live_bytes();
double gc_eff = r->gc_efficiency();
size_t remset_bytes = r->rem_set()->mem_size();
size_t strong_code_roots_bytes = r->rem_set()->strong_code_roots_mem_size();
if (r->used() == 0) {
type = "FREE";
} else if (r->is_survivor()) {
@ -4642,6 +4648,7 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) {
_total_prev_live_bytes += prev_live_bytes;
_total_next_live_bytes += next_live_bytes;
_total_remset_bytes += remset_bytes;
_total_strong_code_roots_bytes += strong_code_roots_bytes;
// Print a line for this particular region.
_out->print_cr(G1PPRL_LINE_PREFIX
@ -4651,9 +4658,11 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) {
G1PPRL_BYTE_FORMAT
G1PPRL_BYTE_FORMAT
G1PPRL_DOUBLE_FORMAT
G1PPRL_BYTE_FORMAT
G1PPRL_BYTE_FORMAT,
type, bottom, end,
used_bytes, prev_live_bytes, next_live_bytes, gc_eff , remset_bytes);
used_bytes, prev_live_bytes, next_live_bytes, gc_eff,
remset_bytes, strong_code_roots_bytes);
return false;
}
@ -4669,7 +4678,8 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() {
G1PPRL_SUM_MB_PERC_FORMAT("used")
G1PPRL_SUM_MB_PERC_FORMAT("prev-live")
G1PPRL_SUM_MB_PERC_FORMAT("next-live")
G1PPRL_SUM_MB_FORMAT("remset"),
G1PPRL_SUM_MB_FORMAT("remset")
G1PPRL_SUM_MB_FORMAT("code-roots"),
bytes_to_mb(_total_capacity_bytes),
bytes_to_mb(_total_used_bytes),
perc(_total_used_bytes, _total_capacity_bytes),
@ -4677,6 +4687,7 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() {
perc(_total_prev_live_bytes, _total_capacity_bytes),
bytes_to_mb(_total_next_live_bytes),
perc(_total_next_live_bytes, _total_capacity_bytes),
bytes_to_mb(_total_remset_bytes));
bytes_to_mb(_total_remset_bytes),
bytes_to_mb(_total_strong_code_roots_bytes));
_out->cr();
}

View File

@ -1257,6 +1257,9 @@ private:
// Accumulator for the remembered set size
size_t _total_remset_bytes;
// Accumulator for strong code roots memory size
size_t _total_strong_code_roots_bytes;
static double perc(size_t val, size_t total) {
if (total == 0) {
return 0.0;

View File

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "gc_implementation/g1/bufferingOopClosure.hpp"
#include "gc_implementation/g1/concurrentG1Refine.hpp"
@ -980,7 +981,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size,
if (should_try_gc) {
bool succeeded;
result = do_collection_pause(word_size, gc_count_before, &succeeded);
result = do_collection_pause(word_size, gc_count_before, &succeeded,
GCCause::_g1_inc_collection_pause);
if (result != NULL) {
assert(succeeded, "only way to get back a non-NULL result");
return result;
@ -1105,7 +1107,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size,
// enough space for the allocation to succeed after the pause.
bool succeeded;
result = do_collection_pause(word_size, gc_count_before, &succeeded);
result = do_collection_pause(word_size, gc_count_before, &succeeded,
GCCause::_g1_humongous_allocation);
if (result != NULL) {
assert(succeeded, "only way to get back a non-NULL result");
return result;
@ -1176,20 +1179,27 @@ class PostMCRemSetClearClosure: public HeapRegionClosure {
ModRefBarrierSet* _mr_bs;
public:
PostMCRemSetClearClosure(G1CollectedHeap* g1h, ModRefBarrierSet* mr_bs) :
_g1h(g1h), _mr_bs(mr_bs) { }
_g1h(g1h), _mr_bs(mr_bs) {}
bool doHeapRegion(HeapRegion* r) {
HeapRegionRemSet* hrrs = r->rem_set();
if (r->continuesHumongous()) {
// We'll assert that the strong code root list and RSet is empty
assert(hrrs->strong_code_roots_list_length() == 0, "sanity");
assert(hrrs->occupied() == 0, "RSet should be empty");
return false;
}
_g1h->reset_gc_time_stamps(r);
HeapRegionRemSet* hrrs = r->rem_set();
if (hrrs != NULL) hrrs->clear();
hrrs->clear();
// You might think here that we could clear just the cards
// corresponding to the used region. But no: if we leave a dirty card
// in a region we might allocate into, then it would prevent that card
// from being enqueued, and cause it to be missed.
// Re: the performance cost: we shouldn't be doing full GC anyway!
_mr_bs->clear(MemRegion(r->bottom(), r->end()));
return false;
}
};
@ -1269,30 +1279,6 @@ void G1CollectedHeap::print_hrs_post_compaction() {
heap_region_iterate(&cl);
}
double G1CollectedHeap::verify(bool guard, const char* msg) {
double verify_time_ms = 0.0;
if (guard && total_collections() >= VerifyGCStartAt) {
double verify_start = os::elapsedTime();
HandleMark hm; // Discard invalid handles created during verification
prepare_for_verify();
Universe::verify(VerifyOption_G1UsePrevMarking, msg);
verify_time_ms = (os::elapsedTime() - verify_start) * 1000;
}
return verify_time_ms;
}
void G1CollectedHeap::verify_before_gc() {
double verify_time_ms = verify(VerifyBeforeGC, " VerifyBeforeGC:");
g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms);
}
void G1CollectedHeap::verify_after_gc() {
double verify_time_ms = verify(VerifyAfterGC, " VerifyAfterGC:");
g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms);
}
bool G1CollectedHeap::do_collection(bool explicit_gc,
bool clear_all_soft_refs,
size_t word_size) {
@ -1433,7 +1419,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
// Delete metaspaces for unloaded class loaders and clean up loader_data graph
ClassLoaderDataGraph::purge();
MetaspaceAux::verify_metrics();
MetaspaceAux::verify_metrics();
// Note: since we've just done a full GC, concurrent
// marking is no longer active. Therefore we need not
@ -1504,6 +1490,9 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
heap_region_iterate(&rebuild_rs);
}
// Rebuild the strong code root lists for each region
rebuild_strong_code_roots();
if (true) { // FIXME
MetaspaceGC::compute_new_size();
}
@ -2019,10 +2008,12 @@ jint G1CollectedHeap::initialize() {
size_t init_byte_size = collector_policy()->initial_heap_byte_size();
size_t max_byte_size = collector_policy()->max_heap_byte_size();
size_t heap_alignment = collector_policy()->max_alignment();
// Ensure that the sizes are properly aligned.
Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap");
Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap");
Universe::check_alignment(max_byte_size, heap_alignment, "g1 heap");
_cg1r = new ConcurrentG1Refine(this);
@ -2039,12 +2030,8 @@ jint G1CollectedHeap::initialize() {
// If this happens then we could end up using a non-optimal
// compressed oops mode.
// Since max_byte_size is aligned to the size of a heap region (checked
// above).
Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap");
ReservedSpace heap_rs = Universe::reserve_heap(max_byte_size,
HeapRegion::GrainBytes);
heap_alignment);
// It is important to do this in a way such that concurrent readers can't
// temporarily think something is in the heap. (I've actually seen this
@ -3109,6 +3096,145 @@ const char* G1CollectedHeap::top_at_mark_start_str(VerifyOption vo) {
return NULL; // keep some compilers happy
}
// TODO: VerifyRootsClosure extends OopsInGenClosure so that we can
// pass it as the perm_blk to SharedHeap::process_strong_roots.
// When process_strong_roots stop calling perm_blk->younger_refs_iterate
// we can change this closure to extend the simpler OopClosure.
class VerifyRootsClosure: public OopsInGenClosure {
private:
G1CollectedHeap* _g1h;
VerifyOption _vo;
bool _failures;
public:
// _vo == UsePrevMarking -> use "prev" marking information,
// _vo == UseNextMarking -> use "next" marking information,
// _vo == UseMarkWord -> use mark word from object header.
VerifyRootsClosure(VerifyOption vo) :
_g1h(G1CollectedHeap::heap()),
_vo(vo),
_failures(false) { }
bool failures() { return _failures; }
template <class T> void do_oop_nv(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (_g1h->is_obj_dead_cond(obj, _vo)) {
gclog_or_tty->print_cr("Root location "PTR_FORMAT" "
"points to dead obj "PTR_FORMAT, p, (void*) obj);
if (_vo == VerifyOption_G1UseMarkWord) {
gclog_or_tty->print_cr(" Mark word: "PTR_FORMAT, (void*)(obj->mark()));
}
obj->print_on(gclog_or_tty);
_failures = true;
}
}
}
void do_oop(oop* p) { do_oop_nv(p); }
void do_oop(narrowOop* p) { do_oop_nv(p); }
};
class G1VerifyCodeRootOopClosure: public OopsInGenClosure {
G1CollectedHeap* _g1h;
OopClosure* _root_cl;
nmethod* _nm;
VerifyOption _vo;
bool _failures;
template <class T> void do_oop_work(T* p) {
// First verify that this root is live
_root_cl->do_oop(p);
if (!G1VerifyHeapRegionCodeRoots) {
// We're not verifying the code roots attached to heap region.
return;
}
// Don't check the code roots during marking verification in a full GC
if (_vo == VerifyOption_G1UseMarkWord) {
return;
}
// Now verify that the current nmethod (which contains p) is
// in the code root list of the heap region containing the
// object referenced by p.
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
// Now fetch the region containing the object
HeapRegion* hr = _g1h->heap_region_containing(obj);
HeapRegionRemSet* hrrs = hr->rem_set();
// Verify that the strong code root list for this region
// contains the nmethod
if (!hrrs->strong_code_roots_list_contains(_nm)) {
gclog_or_tty->print_cr("Code root location "PTR_FORMAT" "
"from nmethod "PTR_FORMAT" not in strong "
"code roots for region ["PTR_FORMAT","PTR_FORMAT")",
p, _nm, hr->bottom(), hr->end());
_failures = true;
}
}
}
public:
G1VerifyCodeRootOopClosure(G1CollectedHeap* g1h, OopClosure* root_cl, VerifyOption vo):
_g1h(g1h), _root_cl(root_cl), _vo(vo), _nm(NULL), _failures(false) {}
void do_oop(oop* p) { do_oop_work(p); }
void do_oop(narrowOop* p) { do_oop_work(p); }
void set_nmethod(nmethod* nm) { _nm = nm; }
bool failures() { return _failures; }
};
class G1VerifyCodeRootBlobClosure: public CodeBlobClosure {
G1VerifyCodeRootOopClosure* _oop_cl;
public:
G1VerifyCodeRootBlobClosure(G1VerifyCodeRootOopClosure* oop_cl):
_oop_cl(oop_cl) {}
void do_code_blob(CodeBlob* cb) {
nmethod* nm = cb->as_nmethod_or_null();
if (nm != NULL) {
_oop_cl->set_nmethod(nm);
nm->oops_do(_oop_cl);
}
}
};
class YoungRefCounterClosure : public OopClosure {
G1CollectedHeap* _g1h;
int _count;
public:
YoungRefCounterClosure(G1CollectedHeap* g1h) : _g1h(g1h), _count(0) {}
void do_oop(oop* p) { if (_g1h->is_in_young(*p)) { _count++; } }
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
int count() { return _count; }
void reset_count() { _count = 0; };
};
class VerifyKlassClosure: public KlassClosure {
YoungRefCounterClosure _young_ref_counter_closure;
OopClosure *_oop_closure;
public:
VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {}
void do_klass(Klass* k) {
k->oops_do(_oop_closure);
_young_ref_counter_closure.reset_count();
k->oops_do(&_young_ref_counter_closure);
if (_young_ref_counter_closure.count() > 0) {
guarantee(k->has_modified_oops(), err_msg("Klass %p, has young refs but is not dirty.", k));
}
}
};
class VerifyLivenessOopClosure: public OopClosure {
G1CollectedHeap* _g1h;
VerifyOption _vo;
@ -3242,75 +3368,7 @@ public:
}
};
class YoungRefCounterClosure : public OopClosure {
G1CollectedHeap* _g1h;
int _count;
public:
YoungRefCounterClosure(G1CollectedHeap* g1h) : _g1h(g1h), _count(0) {}
void do_oop(oop* p) { if (_g1h->is_in_young(*p)) { _count++; } }
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
int count() { return _count; }
void reset_count() { _count = 0; };
};
class VerifyKlassClosure: public KlassClosure {
YoungRefCounterClosure _young_ref_counter_closure;
OopClosure *_oop_closure;
public:
VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {}
void do_klass(Klass* k) {
k->oops_do(_oop_closure);
_young_ref_counter_closure.reset_count();
k->oops_do(&_young_ref_counter_closure);
if (_young_ref_counter_closure.count() > 0) {
guarantee(k->has_modified_oops(), err_msg("Klass %p, has young refs but is not dirty.", k));
}
}
};
// TODO: VerifyRootsClosure extends OopsInGenClosure so that we can
// pass it as the perm_blk to SharedHeap::process_strong_roots.
// When process_strong_roots stop calling perm_blk->younger_refs_iterate
// we can change this closure to extend the simpler OopClosure.
class VerifyRootsClosure: public OopsInGenClosure {
private:
G1CollectedHeap* _g1h;
VerifyOption _vo;
bool _failures;
public:
// _vo == UsePrevMarking -> use "prev" marking information,
// _vo == UseNextMarking -> use "next" marking information,
// _vo == UseMarkWord -> use mark word from object header.
VerifyRootsClosure(VerifyOption vo) :
_g1h(G1CollectedHeap::heap()),
_vo(vo),
_failures(false) { }
bool failures() { return _failures; }
template <class T> void do_oop_nv(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (_g1h->is_obj_dead_cond(obj, _vo)) {
gclog_or_tty->print_cr("Root location "PTR_FORMAT" "
"points to dead obj "PTR_FORMAT, p, (void*) obj);
if (_vo == VerifyOption_G1UseMarkWord) {
gclog_or_tty->print_cr(" Mark word: "PTR_FORMAT, (void*)(obj->mark()));
}
obj->print_on(gclog_or_tty);
_failures = true;
}
}
}
void do_oop(oop* p) { do_oop_nv(p); }
void do_oop(narrowOop* p) { do_oop_nv(p); }
};
// This is the task used for parallel heap verification.
// This is the task used for parallel verification of the heap regions
class G1ParVerifyTask: public AbstractGangTask {
private:
@ -3344,20 +3402,15 @@ public:
}
};
void G1CollectedHeap::verify(bool silent) {
verify(silent, VerifyOption_G1UsePrevMarking);
}
void G1CollectedHeap::verify(bool silent,
VerifyOption vo) {
void G1CollectedHeap::verify(bool silent, VerifyOption vo) {
if (SafepointSynchronize::is_at_safepoint()) {
if (!silent) { gclog_or_tty->print("Roots "); }
VerifyRootsClosure rootsCl(vo);
assert(Thread::current()->is_VM_thread(),
"Expected to be executed serially by the VM thread at this point");
CodeBlobToOopClosure blobsCl(&rootsCl, /*do_marking=*/ false);
if (!silent) { gclog_or_tty->print("Roots "); }
VerifyRootsClosure rootsCl(vo);
G1VerifyCodeRootOopClosure codeRootsCl(this, &rootsCl, vo);
G1VerifyCodeRootBlobClosure blobsCl(&codeRootsCl);
VerifyKlassClosure klassCl(this, &rootsCl);
// We apply the relevant closures to all the oops in the
@ -3376,7 +3429,7 @@ void G1CollectedHeap::verify(bool silent,
&klassCl
);
bool failures = rootsCl.failures();
bool failures = rootsCl.failures() || codeRootsCl.failures();
if (vo != VerifyOption_G1UseMarkWord) {
// If we're verifying during a full GC then the region sets
@ -3445,6 +3498,34 @@ void G1CollectedHeap::verify(bool silent,
}
}
void G1CollectedHeap::verify(bool silent) {
verify(silent, VerifyOption_G1UsePrevMarking);
}
double G1CollectedHeap::verify(bool guard, const char* msg) {
double verify_time_ms = 0.0;
if (guard && total_collections() >= VerifyGCStartAt) {
double verify_start = os::elapsedTime();
HandleMark hm; // Discard invalid handles created during verification
prepare_for_verify();
Universe::verify(VerifyOption_G1UsePrevMarking, msg);
verify_time_ms = (os::elapsedTime() - verify_start) * 1000;
}
return verify_time_ms;
}
void G1CollectedHeap::verify_before_gc() {
double verify_time_ms = verify(VerifyBeforeGC, " VerifyBeforeGC:");
g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms);
}
void G1CollectedHeap::verify_after_gc() {
double verify_time_ms = verify(VerifyAfterGC, " VerifyAfterGC:");
g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms);
}
class PrintRegionClosure: public HeapRegionClosure {
outputStream* _st;
public:
@ -3619,14 +3700,15 @@ void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) {
HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size,
unsigned int gc_count_before,
bool* succeeded) {
bool* succeeded,
GCCause::Cause gc_cause) {
assert_heap_not_locked_and_not_at_safepoint();
g1_policy()->record_stop_world_start();
VM_G1IncCollectionPause op(gc_count_before,
word_size,
false, /* should_initiate_conc_mark */
g1_policy()->max_pause_time_ms(),
GCCause::_g1_inc_collection_pause);
gc_cause);
VMThread::execute(&op);
HeapWord* result = op.result();
@ -3866,8 +3948,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
append_secondary_free_list_if_not_empty_with_lock();
}
assert(check_young_list_well_formed(),
"young list should be well formed");
assert(check_young_list_well_formed(), "young list should be well formed");
assert(check_heap_region_claim_values(HeapRegion::InitialClaimValue),
"sanity check");
// Don't dynamically change the number of GC threads this early. A value of
// 0 is used to indicate serial work. When parallel work is done,
@ -4987,7 +5070,11 @@ public:
G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, &pss);
int so = SharedHeap::SO_AllClasses | SharedHeap::SO_Strings | SharedHeap::SO_CodeCache;
// Don't scan the scavengable methods in the code cache as part
// of strong root scanning. The code roots that point into a
// region in the collection set are scanned when we scan the
// region's RSet.
int so = SharedHeap::SO_AllClasses | SharedHeap::SO_Strings;
pss.start_strong_roots();
_g1h->g1_process_strong_roots(/* is scavenging */ true,
@ -5029,67 +5116,6 @@ public:
// *** Common G1 Evacuation Stuff
// Closures that support the filtering of CodeBlobs scanned during
// external root scanning.
// Closure applied to reference fields in code blobs (specifically nmethods)
// to determine whether an nmethod contains references that point into
// the collection set. Used as a predicate when walking code roots so
// that only nmethods that point into the collection set are added to the
// 'marked' list.
class G1FilteredCodeBlobToOopClosure : public CodeBlobToOopClosure {
class G1PointsIntoCSOopClosure : public OopClosure {
G1CollectedHeap* _g1;
bool _points_into_cs;
public:
G1PointsIntoCSOopClosure(G1CollectedHeap* g1) :
_g1(g1), _points_into_cs(false) { }
bool points_into_cs() const { return _points_into_cs; }
template <class T>
void do_oop_nv(T* p) {
if (!_points_into_cs) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop) &&
_g1->in_cset_fast_test(oopDesc::decode_heap_oop_not_null(heap_oop))) {
_points_into_cs = true;
}
}
}
virtual void do_oop(oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
};
G1CollectedHeap* _g1;
public:
G1FilteredCodeBlobToOopClosure(G1CollectedHeap* g1, OopClosure* cl) :
CodeBlobToOopClosure(cl, true), _g1(g1) { }
virtual void do_code_blob(CodeBlob* cb) {
nmethod* nm = cb->as_nmethod_or_null();
if (nm != NULL && !(nm->test_oops_do_mark())) {
G1PointsIntoCSOopClosure predicate_cl(_g1);
nm->oops_do(&predicate_cl);
if (predicate_cl.points_into_cs()) {
// At least one of the reference fields or the oop relocations
// in the nmethod points into the collection set. We have to
// 'mark' this nmethod.
// Note: Revisit the following if CodeBlobToOopClosure::do_code_blob()
// or MarkingCodeBlobClosure::do_code_blob() change.
if (!nm->test_set_oops_do_mark()) {
do_newly_marked_nmethod(nm);
}
}
}
}
};
// This method is run in a GC worker.
void
@ -5107,9 +5133,10 @@ g1_process_strong_roots(bool is_scavenging,
BufferingOopClosure buf_scan_non_heap_roots(scan_non_heap_roots);
// Walk the code cache w/o buffering, because StarTask cannot handle
// unaligned oop locations.
G1FilteredCodeBlobToOopClosure eager_scan_code_roots(this, scan_non_heap_roots);
assert(so & SO_CodeCache || scan_rs != NULL, "must scan code roots somehow");
// Walk the code cache/strong code roots w/o buffering, because StarTask
// cannot handle unaligned oop locations.
CodeBlobToOopClosure eager_scan_code_roots(scan_non_heap_roots, true /* do_marking */);
process_strong_roots(false, // no scoping; this is parallel code
is_scavenging, so,
@ -5154,9 +5181,22 @@ g1_process_strong_roots(bool is_scavenging,
}
g1_policy()->phase_times()->record_satb_filtering_time(worker_i, satb_filtering_ms);
// If this is an initial mark pause, and we're not scanning
// the entire code cache, we need to mark the oops in the
// strong code root lists for the regions that are not in
// the collection set.
// Note all threads participate in this set of root tasks.
double mark_strong_code_roots_ms = 0.0;
if (g1_policy()->during_initial_mark_pause() && !(so & SO_CodeCache)) {
double mark_strong_roots_start = os::elapsedTime();
mark_strong_code_roots(worker_i);
mark_strong_code_roots_ms = (os::elapsedTime() - mark_strong_roots_start) * 1000.0;
}
g1_policy()->phase_times()->record_strong_code_root_mark_time(worker_i, mark_strong_code_roots_ms);
// Now scan the complement of the collection set.
if (scan_rs != NULL) {
g1_rem_set()->oops_into_collection_set_do(scan_rs, worker_i);
g1_rem_set()->oops_into_collection_set_do(scan_rs, &eager_scan_code_roots, worker_i);
}
_process_strong_tasks->all_tasks_completed();
}
@ -5774,9 +5814,6 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
process_discovered_references(n_workers);
// Weak root processing.
// Note: when JSR 292 is enabled and code blobs can contain
// non-perm oops then we will need to process the code blobs
// here too.
{
G1STWIsAliveClosure is_alive(this);
G1KeepAliveClosure keep_alive(this);
@ -5792,6 +5829,17 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
hot_card_cache->reset_hot_cache();
hot_card_cache->set_use_cache(true);
// Migrate the strong code roots attached to each region in
// the collection set. Ideally we would like to do this
// after we have finished the scanning/evacuation of the
// strong code roots for a particular heap region.
migrate_strong_code_roots();
if (g1_policy()->during_initial_mark_pause()) {
// Reset the claim values set during marking the strong code roots
reset_heap_region_claim_values();
}
finalize_for_evac_failure();
if (evacuation_failed()) {
@ -6588,3 +6636,208 @@ void G1CollectedHeap::verify_region_sets() {
_humongous_set.verify_end();
_free_list.verify_end();
}
// Optimized nmethod scanning
class RegisterNMethodOopClosure: public OopClosure {
G1CollectedHeap* _g1h;
nmethod* _nm;
template <class T> void do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
HeapRegion* hr = _g1h->heap_region_containing(obj);
assert(!hr->isHumongous(), "code root in humongous region?");
// HeapRegion::add_strong_code_root() avoids adding duplicate
// entries but having duplicates is OK since we "mark" nmethods
// as visited when we scan the strong code root lists during the GC.
hr->add_strong_code_root(_nm);
assert(hr->rem_set()->strong_code_roots_list_contains(_nm), "add failed?");
}
}
public:
RegisterNMethodOopClosure(G1CollectedHeap* g1h, nmethod* nm) :
_g1h(g1h), _nm(nm) {}
void do_oop(oop* p) { do_oop_work(p); }
void do_oop(narrowOop* p) { do_oop_work(p); }
};
class UnregisterNMethodOopClosure: public OopClosure {
G1CollectedHeap* _g1h;
nmethod* _nm;
template <class T> void do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
HeapRegion* hr = _g1h->heap_region_containing(obj);
assert(!hr->isHumongous(), "code root in humongous region?");
hr->remove_strong_code_root(_nm);
assert(!hr->rem_set()->strong_code_roots_list_contains(_nm), "remove failed?");
}
}
public:
UnregisterNMethodOopClosure(G1CollectedHeap* g1h, nmethod* nm) :
_g1h(g1h), _nm(nm) {}
void do_oop(oop* p) { do_oop_work(p); }
void do_oop(narrowOop* p) { do_oop_work(p); }
};
void G1CollectedHeap::register_nmethod(nmethod* nm) {
CollectedHeap::register_nmethod(nm);
guarantee(nm != NULL, "sanity");
RegisterNMethodOopClosure reg_cl(this, nm);
nm->oops_do(&reg_cl);
}
void G1CollectedHeap::unregister_nmethod(nmethod* nm) {
CollectedHeap::unregister_nmethod(nm);
guarantee(nm != NULL, "sanity");
UnregisterNMethodOopClosure reg_cl(this, nm);
nm->oops_do(&reg_cl, true);
}
class MigrateCodeRootsHeapRegionClosure: public HeapRegionClosure {
public:
bool doHeapRegion(HeapRegion *hr) {
assert(!hr->isHumongous(), "humongous region in collection set?");
hr->migrate_strong_code_roots();
return false;
}
};
void G1CollectedHeap::migrate_strong_code_roots() {
MigrateCodeRootsHeapRegionClosure cl;
double migrate_start = os::elapsedTime();
collection_set_iterate(&cl);
double migration_time_ms = (os::elapsedTime() - migrate_start) * 1000.0;
g1_policy()->phase_times()->record_strong_code_root_migration_time(migration_time_ms);
}
// Mark all the code roots that point into regions *not* in the
// collection set.
//
// Note we do not want to use a "marking" CodeBlobToOopClosure while
// walking the the code roots lists of regions not in the collection
// set. Suppose we have an nmethod (M) that points to objects in two
// separate regions - one in the collection set (R1) and one not (R2).
// Using a "marking" CodeBlobToOopClosure here would result in "marking"
// nmethod M when walking the code roots for R1. When we come to scan
// the code roots for R2, we would see that M is already marked and it
// would be skipped and the objects in R2 that are referenced from M
// would not be evacuated.
class MarkStrongCodeRootCodeBlobClosure: public CodeBlobClosure {
class MarkStrongCodeRootOopClosure: public OopClosure {
ConcurrentMark* _cm;
HeapRegion* _hr;
uint _worker_id;
template <class T> void do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
// Only mark objects in the region (which is assumed
// to be not in the collection set).
if (_hr->is_in(obj)) {
_cm->grayRoot(obj, (size_t) obj->size(), _worker_id);
}
}
}
public:
MarkStrongCodeRootOopClosure(ConcurrentMark* cm, HeapRegion* hr, uint worker_id) :
_cm(cm), _hr(hr), _worker_id(worker_id) {
assert(!_hr->in_collection_set(), "sanity");
}
void do_oop(narrowOop* p) { do_oop_work(p); }
void do_oop(oop* p) { do_oop_work(p); }
};
MarkStrongCodeRootOopClosure _oop_cl;
public:
MarkStrongCodeRootCodeBlobClosure(ConcurrentMark* cm, HeapRegion* hr, uint worker_id):
_oop_cl(cm, hr, worker_id) {}
void do_code_blob(CodeBlob* cb) {
nmethod* nm = (cb == NULL) ? NULL : cb->as_nmethod_or_null();
if (nm != NULL) {
nm->oops_do(&_oop_cl);
}
}
};
class MarkStrongCodeRootsHRClosure: public HeapRegionClosure {
G1CollectedHeap* _g1h;
uint _worker_id;
public:
MarkStrongCodeRootsHRClosure(G1CollectedHeap* g1h, uint worker_id) :
_g1h(g1h), _worker_id(worker_id) {}
bool doHeapRegion(HeapRegion *hr) {
HeapRegionRemSet* hrrs = hr->rem_set();
if (hr->isHumongous()) {
// Code roots should never be attached to a humongous region
assert(hrrs->strong_code_roots_list_length() == 0, "sanity");
return false;
}
if (hr->in_collection_set()) {
// Don't mark code roots into regions in the collection set here.
// They will be marked when we scan them.
return false;
}
MarkStrongCodeRootCodeBlobClosure cb_cl(_g1h->concurrent_mark(), hr, _worker_id);
hr->strong_code_roots_do(&cb_cl);
return false;
}
};
void G1CollectedHeap::mark_strong_code_roots(uint worker_id) {
MarkStrongCodeRootsHRClosure cl(this, worker_id);
if (G1CollectedHeap::use_parallel_gc_threads()) {
heap_region_par_iterate_chunked(&cl,
worker_id,
workers()->active_workers(),
HeapRegion::ParMarkRootClaimValue);
} else {
heap_region_iterate(&cl);
}
}
class RebuildStrongCodeRootClosure: public CodeBlobClosure {
G1CollectedHeap* _g1h;
public:
RebuildStrongCodeRootClosure(G1CollectedHeap* g1h) :
_g1h(g1h) {}
void do_code_blob(CodeBlob* cb) {
nmethod* nm = (cb != NULL) ? cb->as_nmethod_or_null() : NULL;
if (nm == NULL) {
return;
}
if (ScavengeRootsInCode && nm->detect_scavenge_root_oops()) {
_g1h->register_nmethod(nm);
}
}
};
void G1CollectedHeap::rebuild_strong_code_roots() {
RebuildStrongCodeRootClosure blob_cl(this);
CodeCache::blobs_do(&blob_cl);
}

View File

@ -46,6 +46,7 @@
// may combine concurrent marking with parallel, incremental compaction of
// heap subsets that will yield large amounts of garbage.
// Forward declarations
class HeapRegion;
class HRRSCleanupTask;
class GenerationSpec;
@ -69,6 +70,7 @@ class STWGCTimer;
class G1NewTracer;
class G1OldTracer;
class EvacuationFailedInfo;
class nmethod;
typedef OverflowTaskQueue<StarTask, mtGC> RefToScanQueue;
typedef GenericTaskQueueSet<RefToScanQueue, mtGC> RefToScanQueueSet;
@ -163,18 +165,6 @@ public:
: G1AllocRegion("Mutator Alloc Region", false /* bot_updates */) { }
};
// The G1 STW is alive closure.
// An instance is embedded into the G1CH and used as the
// (optional) _is_alive_non_header closure in the STW
// reference processor. It is also extensively used during
// reference processing during STW evacuation pauses.
class G1STWIsAliveClosure: public BoolObjectClosure {
G1CollectedHeap* _g1;
public:
G1STWIsAliveClosure(G1CollectedHeap* g1) : _g1(g1) {}
bool do_object_b(oop p);
};
class SurvivorGCAllocRegion : public G1AllocRegion {
protected:
virtual HeapRegion* allocate_new_region(size_t word_size, bool force);
@ -193,6 +183,18 @@ public:
: G1AllocRegion("Old GC Alloc Region", true /* bot_updates */) { }
};
// The G1 STW is alive closure.
// An instance is embedded into the G1CH and used as the
// (optional) _is_alive_non_header closure in the STW
// reference processor. It is also extensively used during
// reference processing during STW evacuation pauses.
class G1STWIsAliveClosure: public BoolObjectClosure {
G1CollectedHeap* _g1;
public:
G1STWIsAliveClosure(G1CollectedHeap* g1) : _g1(g1) {}
bool do_object_b(oop p);
};
class RefineCardTableEntryClosure;
class G1CollectedHeap : public SharedHeap {
@ -774,9 +776,10 @@ protected:
// it has to be read while holding the Heap_lock. Currently, both
// methods that call do_collection_pause() release the Heap_lock
// before the call, so it's easy to read gc_count_before just before.
HeapWord* do_collection_pause(size_t word_size,
unsigned int gc_count_before,
bool* succeeded);
HeapWord* do_collection_pause(size_t word_size,
unsigned int gc_count_before,
bool* succeeded,
GCCause::Cause gc_cause);
// The guts of the incremental collection pause, executed by the vm
// thread. It returns false if it is unable to do the collection due
@ -1549,42 +1552,6 @@ public:
virtual jlong millis_since_last_gc();
// Perform any cleanup actions necessary before allowing a verification.
virtual void prepare_for_verify();
// Perform verification.
// vo == UsePrevMarking -> use "prev" marking information,
// vo == UseNextMarking -> use "next" marking information
// vo == UseMarkWord -> use the mark word in the object header
//
// NOTE: Only the "prev" marking information is guaranteed to be
// consistent most of the time, so most calls to this should use
// vo == UsePrevMarking.
// Currently, there is only one case where this is called with
// vo == UseNextMarking, which is to verify the "next" marking
// information at the end of remark.
// Currently there is only one place where this is called with
// vo == UseMarkWord, which is to verify the marking during a
// full GC.
void verify(bool silent, VerifyOption vo);
// Override; it uses the "prev" marking information
virtual void verify(bool silent);
virtual void print_on(outputStream* st) const;
virtual void print_extended_on(outputStream* st) const;
virtual void print_on_error(outputStream* st) const;
virtual void print_gc_threads_on(outputStream* st) const;
virtual void gc_threads_do(ThreadClosure* tc) const;
// Override
void print_tracing_info() const;
// The following two methods are helpful for debugging RSet issues.
void print_cset_rsets() PRODUCT_RETURN;
void print_all_rsets() PRODUCT_RETURN;
// Convenience function to be used in situations where the heap type can be
// asserted to be this type.
@ -1661,13 +1628,86 @@ public:
else return is_obj_ill(obj, hr);
}
bool allocated_since_marking(oop obj, HeapRegion* hr, VerifyOption vo);
HeapWord* top_at_mark_start(HeapRegion* hr, VerifyOption vo);
bool is_marked(oop obj, VerifyOption vo);
const char* top_at_mark_start_str(VerifyOption vo);
ConcurrentMark* concurrent_mark() const { return _cm; }
// Refinement
ConcurrentG1Refine* concurrent_g1_refine() const { return _cg1r; }
// The dirty cards region list is used to record a subset of regions
// whose cards need clearing. The list if populated during the
// remembered set scanning and drained during the card table
// cleanup. Although the methods are reentrant, population/draining
// phases must not overlap. For synchronization purposes the last
// element on the list points to itself.
HeapRegion* _dirty_cards_region_list;
void push_dirty_cards_region(HeapRegion* hr);
HeapRegion* pop_dirty_cards_region();
// Optimized nmethod scanning support routines
// Register the given nmethod with the G1 heap
virtual void register_nmethod(nmethod* nm);
// Unregister the given nmethod from the G1 heap
virtual void unregister_nmethod(nmethod* nm);
// Migrate the nmethods in the code root lists of the regions
// in the collection set to regions in to-space. In the event
// of an evacuation failure, nmethods that reference objects
// that were not successfullly evacuated are not migrated.
void migrate_strong_code_roots();
// During an initial mark pause, mark all the code roots that
// point into regions *not* in the collection set.
void mark_strong_code_roots(uint worker_id);
// Rebuild the stong code root lists for each region
// after a full GC
void rebuild_strong_code_roots();
// Verification
// The following is just to alert the verification code
// that a full collection has occurred and that the
// remembered sets are no longer up to date.
bool _full_collection;
void set_full_collection() { _full_collection = true;}
void clear_full_collection() {_full_collection = false;}
bool full_collection() {return _full_collection;}
// Perform any cleanup actions necessary before allowing a verification.
virtual void prepare_for_verify();
// Perform verification.
// vo == UsePrevMarking -> use "prev" marking information,
// vo == UseNextMarking -> use "next" marking information
// vo == UseMarkWord -> use the mark word in the object header
//
// NOTE: Only the "prev" marking information is guaranteed to be
// consistent most of the time, so most calls to this should use
// vo == UsePrevMarking.
// Currently, there is only one case where this is called with
// vo == UseNextMarking, which is to verify the "next" marking
// information at the end of remark.
// Currently there is only one place where this is called with
// vo == UseMarkWord, which is to verify the marking during a
// full GC.
void verify(bool silent, VerifyOption vo);
// Override; it uses the "prev" marking information
virtual void verify(bool silent);
// The methods below are here for convenience and dispatch the
// appropriate method depending on value of the given VerifyOption
// parameter. The options for that parameter are:
//
// vo == UsePrevMarking -> use "prev" marking information,
// vo == UseNextMarking -> use "next" marking information,
// vo == UseMarkWord -> use mark word from object header
// parameter. The values for that parameter, and their meanings,
// are the same as those above.
bool is_obj_dead_cond(const oop obj,
const HeapRegion* hr,
@ -1692,31 +1732,21 @@ public:
return false; // keep some compilers happy
}
bool allocated_since_marking(oop obj, HeapRegion* hr, VerifyOption vo);
HeapWord* top_at_mark_start(HeapRegion* hr, VerifyOption vo);
bool is_marked(oop obj, VerifyOption vo);
const char* top_at_mark_start_str(VerifyOption vo);
// Printing
// The following is just to alert the verification code
// that a full collection has occurred and that the
// remembered sets are no longer up to date.
bool _full_collection;
void set_full_collection() { _full_collection = true;}
void clear_full_collection() {_full_collection = false;}
bool full_collection() {return _full_collection;}
virtual void print_on(outputStream* st) const;
virtual void print_extended_on(outputStream* st) const;
virtual void print_on_error(outputStream* st) const;
ConcurrentMark* concurrent_mark() const { return _cm; }
ConcurrentG1Refine* concurrent_g1_refine() const { return _cg1r; }
virtual void print_gc_threads_on(outputStream* st) const;
virtual void gc_threads_do(ThreadClosure* tc) const;
// The dirty cards region list is used to record a subset of regions
// whose cards need clearing. The list if populated during the
// remembered set scanning and drained during the card table
// cleanup. Although the methods are reentrant, population/draining
// phases must not overlap. For synchronization purposes the last
// element on the list points to itself.
HeapRegion* _dirty_cards_region_list;
void push_dirty_cards_region(HeapRegion* hr);
HeapRegion* pop_dirty_cards_region();
// Override
void print_tracing_info() const;
// The following two methods are helpful for debugging RSet issues.
void print_cset_rsets() PRODUCT_RETURN;
void print_all_rsets() PRODUCT_RETURN;
public:
void stop_conc_gc_threads();

View File

@ -313,7 +313,8 @@ G1CollectorPolicy::G1CollectorPolicy() :
void G1CollectorPolicy::initialize_flags() {
set_min_alignment(HeapRegion::GrainBytes);
size_t card_table_alignment = GenRemSet::max_alignment_constraint(rem_set_name());
set_max_alignment(MAX2(card_table_alignment, min_alignment()));
size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size();
set_max_alignment(MAX3(card_table_alignment, min_alignment(), page_size));
if (SurvivorRatio < 1) {
vm_exit_during_initialization("Invalid survivor ratio specified");
}

View File

@ -161,6 +161,8 @@ G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) :
_last_update_rs_times_ms(_max_gc_threads, "%.1lf"),
_last_update_rs_processed_buffers(_max_gc_threads, "%d"),
_last_scan_rs_times_ms(_max_gc_threads, "%.1lf"),
_last_strong_code_root_scan_times_ms(_max_gc_threads, "%.1lf"),
_last_strong_code_root_mark_times_ms(_max_gc_threads, "%.1lf"),
_last_obj_copy_times_ms(_max_gc_threads, "%.1lf"),
_last_termination_times_ms(_max_gc_threads, "%.1lf"),
_last_termination_attempts(_max_gc_threads, SIZE_FORMAT),
@ -182,6 +184,8 @@ void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) {
_last_update_rs_times_ms.reset();
_last_update_rs_processed_buffers.reset();
_last_scan_rs_times_ms.reset();
_last_strong_code_root_scan_times_ms.reset();
_last_strong_code_root_mark_times_ms.reset();
_last_obj_copy_times_ms.reset();
_last_termination_times_ms.reset();
_last_termination_attempts.reset();
@ -197,6 +201,8 @@ void G1GCPhaseTimes::note_gc_end() {
_last_update_rs_times_ms.verify();
_last_update_rs_processed_buffers.verify();
_last_scan_rs_times_ms.verify();
_last_strong_code_root_scan_times_ms.verify();
_last_strong_code_root_mark_times_ms.verify();
_last_obj_copy_times_ms.verify();
_last_termination_times_ms.verify();
_last_termination_attempts.verify();
@ -210,6 +216,8 @@ void G1GCPhaseTimes::note_gc_end() {
_last_satb_filtering_times_ms.get(i) +
_last_update_rs_times_ms.get(i) +
_last_scan_rs_times_ms.get(i) +
_last_strong_code_root_scan_times_ms.get(i) +
_last_strong_code_root_mark_times_ms.get(i) +
_last_obj_copy_times_ms.get(i) +
_last_termination_times_ms.get(i);
@ -239,6 +247,9 @@ double G1GCPhaseTimes::accounted_time_ms() {
// Now subtract the time taken to fix up roots in generated code
misc_time_ms += _cur_collection_code_root_fixup_time_ms;
// Strong code root migration time
misc_time_ms += _cur_strong_code_root_migration_time_ms;
// Subtract the time taken to clean the card table from the
// current value of "other time"
misc_time_ms += _cur_clear_ct_time_ms;
@ -257,9 +268,13 @@ void G1GCPhaseTimes::print(double pause_time_sec) {
if (_last_satb_filtering_times_ms.sum() > 0.0) {
_last_satb_filtering_times_ms.print(2, "SATB Filtering (ms)");
}
if (_last_strong_code_root_mark_times_ms.sum() > 0.0) {
_last_strong_code_root_mark_times_ms.print(2, "Code Root Marking (ms)");
}
_last_update_rs_times_ms.print(2, "Update RS (ms)");
_last_update_rs_processed_buffers.print(3, "Processed Buffers");
_last_scan_rs_times_ms.print(2, "Scan RS (ms)");
_last_strong_code_root_scan_times_ms.print(2, "Code Root Scanning (ms)");
_last_obj_copy_times_ms.print(2, "Object Copy (ms)");
_last_termination_times_ms.print(2, "Termination (ms)");
if (G1Log::finest()) {
@ -273,12 +288,17 @@ void G1GCPhaseTimes::print(double pause_time_sec) {
if (_last_satb_filtering_times_ms.sum() > 0.0) {
_last_satb_filtering_times_ms.print(1, "SATB Filtering (ms)");
}
if (_last_strong_code_root_mark_times_ms.sum() > 0.0) {
_last_strong_code_root_mark_times_ms.print(1, "Code Root Marking (ms)");
}
_last_update_rs_times_ms.print(1, "Update RS (ms)");
_last_update_rs_processed_buffers.print(2, "Processed Buffers");
_last_scan_rs_times_ms.print(1, "Scan RS (ms)");
_last_strong_code_root_scan_times_ms.print(1, "Code Root Scanning (ms)");
_last_obj_copy_times_ms.print(1, "Object Copy (ms)");
}
print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms);
print_stats(1, "Code Root Migration", _cur_strong_code_root_migration_time_ms);
print_stats(1, "Clear CT", _cur_clear_ct_time_ms);
double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms();
print_stats(1, "Other", misc_time_ms);

View File

@ -119,6 +119,8 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
WorkerDataArray<double> _last_update_rs_times_ms;
WorkerDataArray<int> _last_update_rs_processed_buffers;
WorkerDataArray<double> _last_scan_rs_times_ms;
WorkerDataArray<double> _last_strong_code_root_scan_times_ms;
WorkerDataArray<double> _last_strong_code_root_mark_times_ms;
WorkerDataArray<double> _last_obj_copy_times_ms;
WorkerDataArray<double> _last_termination_times_ms;
WorkerDataArray<size_t> _last_termination_attempts;
@ -128,6 +130,7 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
double _cur_collection_par_time_ms;
double _cur_collection_code_root_fixup_time_ms;
double _cur_strong_code_root_migration_time_ms;
double _cur_clear_ct_time_ms;
double _cur_ref_proc_time_ms;
@ -179,6 +182,14 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
_last_scan_rs_times_ms.set(worker_i, ms);
}
void record_strong_code_root_scan_time(uint worker_i, double ms) {
_last_strong_code_root_scan_times_ms.set(worker_i, ms);
}
void record_strong_code_root_mark_time(uint worker_i, double ms) {
_last_strong_code_root_mark_times_ms.set(worker_i, ms);
}
void record_obj_copy_time(uint worker_i, double ms) {
_last_obj_copy_times_ms.set(worker_i, ms);
}
@ -208,6 +219,10 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
_cur_collection_code_root_fixup_time_ms = ms;
}
void record_strong_code_root_migration_time(double ms) {
_cur_strong_code_root_migration_time_ms = ms;
}
void record_ref_proc_time(double ms) {
_cur_ref_proc_time_ms = ms;
}
@ -294,6 +309,14 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
return _last_scan_rs_times_ms.average();
}
double average_last_strong_code_root_scan_time(){
return _last_strong_code_root_scan_times_ms.average();
}
double average_last_strong_code_root_mark_time(){
return _last_strong_code_root_mark_times_ms.average();
}
double average_last_obj_copy_time() {
return _last_obj_copy_times_ms.average();
}

View File

@ -262,6 +262,7 @@ void G1MonitoringSupport::update_sizes() {
old_collection_counters()->update_all();
young_collection_counters()->update_all();
MetaspaceCounters::update_performance_counters();
CompressedClassSpaceCounters::update_performance_counters();
}
}

View File

@ -104,15 +104,25 @@ void CountNonCleanMemRegionClosure::do_MemRegion(MemRegion mr) {
class ScanRSClosure : public HeapRegionClosure {
size_t _cards_done, _cards;
G1CollectedHeap* _g1h;
OopsInHeapRegionClosure* _oc;
CodeBlobToOopClosure* _code_root_cl;
G1BlockOffsetSharedArray* _bot_shared;
CardTableModRefBS *_ct_bs;
int _worker_i;
int _block_size;
bool _try_claimed;
double _strong_code_root_scan_time_sec;
int _worker_i;
int _block_size;
bool _try_claimed;
public:
ScanRSClosure(OopsInHeapRegionClosure* oc, int worker_i) :
ScanRSClosure(OopsInHeapRegionClosure* oc,
CodeBlobToOopClosure* code_root_cl,
int worker_i) :
_oc(oc),
_code_root_cl(code_root_cl),
_strong_code_root_scan_time_sec(0.0),
_cards(0),
_cards_done(0),
_worker_i(worker_i),
@ -160,6 +170,12 @@ public:
card_start, card_start + G1BlockOffsetSharedArray::N_words);
}
void scan_strong_code_roots(HeapRegion* r) {
double scan_start = os::elapsedTime();
r->strong_code_roots_do(_code_root_cl);
_strong_code_root_scan_time_sec += (os::elapsedTime() - scan_start);
}
bool doHeapRegion(HeapRegion* r) {
assert(r->in_collection_set(), "should only be called on elements of CS.");
HeapRegionRemSet* hrrs = r->rem_set();
@ -173,6 +189,7 @@ public:
// _try_claimed || r->claim_iter()
// is true: either we're supposed to work on claimed-but-not-complete
// regions, or we successfully claimed the region.
HeapRegionRemSetIterator iter(hrrs);
size_t card_index;
@ -205,30 +222,43 @@ public:
}
}
if (!_try_claimed) {
// Scan the strong code root list attached to the current region
scan_strong_code_roots(r);
hrrs->set_iter_complete();
}
return false;
}
double strong_code_root_scan_time_sec() {
return _strong_code_root_scan_time_sec;
}
size_t cards_done() { return _cards_done;}
size_t cards_looked_up() { return _cards;}
};
void G1RemSet::scanRS(OopsInHeapRegionClosure* oc, int worker_i) {
void G1RemSet::scanRS(OopsInHeapRegionClosure* oc,
CodeBlobToOopClosure* code_root_cl,
int worker_i) {
double rs_time_start = os::elapsedTime();
HeapRegion *startRegion = _g1->start_cset_region_for_worker(worker_i);
ScanRSClosure scanRScl(oc, worker_i);
ScanRSClosure scanRScl(oc, code_root_cl, worker_i);
_g1->collection_set_iterate_from(startRegion, &scanRScl);
scanRScl.set_try_claimed();
_g1->collection_set_iterate_from(startRegion, &scanRScl);
double scan_rs_time_sec = os::elapsedTime() - rs_time_start;
double scan_rs_time_sec = (os::elapsedTime() - rs_time_start)
- scanRScl.strong_code_root_scan_time_sec();
assert( _cards_scanned != NULL, "invariant" );
assert(_cards_scanned != NULL, "invariant");
_cards_scanned[worker_i] = scanRScl.cards_done();
_g1p->phase_times()->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0);
_g1p->phase_times()->record_strong_code_root_scan_time(worker_i,
scanRScl.strong_code_root_scan_time_sec() * 1000.0);
}
// Closure used for updating RSets and recording references that
@ -288,7 +318,8 @@ void G1RemSet::cleanupHRRS() {
}
void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
int worker_i) {
CodeBlobToOopClosure* code_root_cl,
int worker_i) {
#if CARD_REPEAT_HISTO
ct_freq_update_histo_and_reset();
#endif
@ -328,7 +359,7 @@ void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
_g1p->phase_times()->record_update_rs_time(worker_i, 0.0);
}
if (G1UseParallelRSetScanning || (worker_i == 0)) {
scanRS(oc, worker_i);
scanRS(oc, code_root_cl, worker_i);
} else {
_g1p->phase_times()->record_scan_rs_time(worker_i, 0.0);
}

View File

@ -81,14 +81,23 @@ public:
G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs);
~G1RemSet();
// Invoke "blk->do_oop" on all pointers into the CS in objects in regions
// outside the CS (having invoked "blk->set_region" to set the "from"
// region correctly beforehand.) The "worker_i" param is for the
// parallel case where the number of the worker thread calling this
// function can be helpful in partitioning the work to be done. It
// should be the same as the "i" passed to the calling thread's
// work(i) function. In the sequential case this param will be ingored.
void oops_into_collection_set_do(OopsInHeapRegionClosure* blk, int worker_i);
// Invoke "blk->do_oop" on all pointers into the collection set
// from objects in regions outside the collection set (having
// invoked "blk->set_region" to set the "from" region correctly
// beforehand.)
//
// Invoke code_root_cl->do_code_blob on the unmarked nmethods
// on the strong code roots list for each region in the
// collection set.
//
// The "worker_i" param is for the parallel case where the id
// of the worker thread calling this function can be helpful in
// partitioning the work to be done. It should be the same as
// the "i" passed to the calling thread's work(i) function.
// In the sequential case this param will be ignored.
void oops_into_collection_set_do(OopsInHeapRegionClosure* blk,
CodeBlobToOopClosure* code_root_cl,
int worker_i);
// Prepare for and cleanup after an oops_into_collection_set_do
// call. Must call each of these once before and after (in sequential
@ -98,7 +107,10 @@ public:
void prepare_for_oops_into_collection_set_do();
void cleanup_after_oops_into_collection_set_do();
void scanRS(OopsInHeapRegionClosure* oc, int worker_i);
void scanRS(OopsInHeapRegionClosure* oc,
CodeBlobToOopClosure* code_root_cl,
int worker_i);
void updateRS(DirtyCardQueue* into_cset_dcq, int worker_i);
CardTableModRefBS* ct_bs() { return _ct_bs; }

View File

@ -127,32 +127,55 @@ void G1RemSetSummary::subtract_from(G1RemSetSummary* other) {
class HRRSStatsIter: public HeapRegionClosure {
size_t _occupied;
size_t _total_mem_sz;
size_t _max_mem_sz;
HeapRegion* _max_mem_sz_region;
size_t _total_rs_mem_sz;
size_t _max_rs_mem_sz;
HeapRegion* _max_rs_mem_sz_region;
size_t _total_code_root_mem_sz;
size_t _max_code_root_mem_sz;
HeapRegion* _max_code_root_mem_sz_region;
public:
HRRSStatsIter() :
_occupied(0),
_total_mem_sz(0),
_max_mem_sz(0),
_max_mem_sz_region(NULL)
_total_rs_mem_sz(0),
_max_rs_mem_sz(0),
_max_rs_mem_sz_region(NULL),
_total_code_root_mem_sz(0),
_max_code_root_mem_sz(0),
_max_code_root_mem_sz_region(NULL)
{}
bool doHeapRegion(HeapRegion* r) {
size_t mem_sz = r->rem_set()->mem_size();
if (mem_sz > _max_mem_sz) {
_max_mem_sz = mem_sz;
_max_mem_sz_region = r;
HeapRegionRemSet* hrrs = r->rem_set();
// HeapRegionRemSet::mem_size() includes the
// size of the strong code roots
size_t rs_mem_sz = hrrs->mem_size();
if (rs_mem_sz > _max_rs_mem_sz) {
_max_rs_mem_sz = rs_mem_sz;
_max_rs_mem_sz_region = r;
}
_total_mem_sz += mem_sz;
size_t occ = r->rem_set()->occupied();
_total_rs_mem_sz += rs_mem_sz;
size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size();
if (code_root_mem_sz > _max_code_root_mem_sz) {
_max_code_root_mem_sz = code_root_mem_sz;
_max_code_root_mem_sz_region = r;
}
_total_code_root_mem_sz += code_root_mem_sz;
size_t occ = hrrs->occupied();
_occupied += occ;
return false;
}
size_t total_mem_sz() { return _total_mem_sz; }
size_t max_mem_sz() { return _max_mem_sz; }
size_t total_rs_mem_sz() { return _total_rs_mem_sz; }
size_t max_rs_mem_sz() { return _max_rs_mem_sz; }
HeapRegion* max_rs_mem_sz_region() { return _max_rs_mem_sz_region; }
size_t total_code_root_mem_sz() { return _total_code_root_mem_sz; }
size_t max_code_root_mem_sz() { return _max_code_root_mem_sz; }
HeapRegion* max_code_root_mem_sz_region() { return _max_code_root_mem_sz_region; }
size_t occupied() { return _occupied; }
HeapRegion* max_mem_sz_region() { return _max_mem_sz_region; }
};
double calc_percentage(size_t numerator, size_t denominator) {
@ -184,22 +207,33 @@ void G1RemSetSummary::print_on(outputStream* out) {
HRRSStatsIter blk;
G1CollectedHeap::heap()->heap_region_iterate(&blk);
// RemSet stats
out->print_cr(" Total heap region rem set sizes = "SIZE_FORMAT"K."
" Max = "SIZE_FORMAT"K.",
blk.total_mem_sz()/K, blk.max_mem_sz()/K);
blk.total_rs_mem_sz()/K, blk.max_rs_mem_sz()/K);
out->print_cr(" Static structures = "SIZE_FORMAT"K,"
" free_lists = "SIZE_FORMAT"K.",
HeapRegionRemSet::static_mem_size() / K,
HeapRegionRemSet::fl_mem_size() / K);
out->print_cr(" "SIZE_FORMAT" occupied cards represented.",
blk.occupied());
HeapRegion* max_mem_sz_region = blk.max_mem_sz_region();
HeapRegionRemSet* rem_set = max_mem_sz_region->rem_set();
HeapRegion* max_rs_mem_sz_region = blk.max_rs_mem_sz_region();
HeapRegionRemSet* max_rs_rem_set = max_rs_mem_sz_region->rem_set();
out->print_cr(" Max size region = "HR_FORMAT", "
"size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.",
HR_FORMAT_PARAMS(max_mem_sz_region),
(rem_set->mem_size() + K - 1)/K,
(rem_set->occupied() + K - 1)/K);
HR_FORMAT_PARAMS(max_rs_mem_sz_region),
(max_rs_rem_set->mem_size() + K - 1)/K,
(max_rs_rem_set->occupied() + K - 1)/K);
out->print_cr(" Did %d coarsenings.", num_coarsenings());
// Strong code root stats
out->print_cr(" Total heap region code-root set sizes = "SIZE_FORMAT"K."
" Max = "SIZE_FORMAT"K.",
blk.total_code_root_mem_sz()/K, blk.max_code_root_mem_sz()/K);
HeapRegion* max_code_root_mem_sz_region = blk.max_code_root_mem_sz_region();
HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region->rem_set();
out->print_cr(" Max size region = "HR_FORMAT", "
"size = "SIZE_FORMAT "K, num_elems = "SIZE_FORMAT".",
HR_FORMAT_PARAMS(max_code_root_mem_sz_region),
(max_code_root_rem_set->strong_code_roots_mem_size() + K - 1)/K,
(max_code_root_rem_set->strong_code_roots_list_length()));
}

View File

@ -319,7 +319,10 @@
\
diagnostic(bool, G1VerifyRSetsDuringFullGC, false, \
"If true, perform verification of each heap region's " \
"remembered set when verifying the heap during a full GC.")
"remembered set when verifying the heap during a full GC.") \
\
diagnostic(bool, G1VerifyHeapRegionCodeRoots, false, \
"Verify the code root lists attached to each heap region.")
G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG)

View File

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "code/nmethod.hpp"
#include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp"
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
@ -50,144 +51,6 @@ FilterOutOfRegionClosure::FilterOutOfRegionClosure(HeapRegion* r,
OopClosure* oc) :
_r_bottom(r->bottom()), _r_end(r->end()), _oc(oc) { }
class VerifyLiveClosure: public OopClosure {
private:
G1CollectedHeap* _g1h;
CardTableModRefBS* _bs;
oop _containing_obj;
bool _failures;
int _n_failures;
VerifyOption _vo;
public:
// _vo == UsePrevMarking -> use "prev" marking information,
// _vo == UseNextMarking -> use "next" marking information,
// _vo == UseMarkWord -> use mark word from object header.
VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) :
_g1h(g1h), _bs(NULL), _containing_obj(NULL),
_failures(false), _n_failures(0), _vo(vo)
{
BarrierSet* bs = _g1h->barrier_set();
if (bs->is_a(BarrierSet::CardTableModRef))
_bs = (CardTableModRefBS*)bs;
}
void set_containing_obj(oop obj) {
_containing_obj = obj;
}
bool failures() { return _failures; }
int n_failures() { return _n_failures; }
virtual void do_oop(narrowOop* p) { do_oop_work(p); }
virtual void do_oop( oop* p) { do_oop_work(p); }
void print_object(outputStream* out, oop obj) {
#ifdef PRODUCT
Klass* k = obj->klass();
const char* class_name = InstanceKlass::cast(k)->external_name();
out->print_cr("class name %s", class_name);
#else // PRODUCT
obj->print_on(out);
#endif // PRODUCT
}
template <class T>
void do_oop_work(T* p) {
assert(_containing_obj != NULL, "Precondition");
assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo),
"Precondition");
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
bool failed = false;
if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) {
MutexLockerEx x(ParGCRareEvent_lock,
Mutex::_no_safepoint_check_flag);
if (!_failures) {
gclog_or_tty->print_cr("");
gclog_or_tty->print_cr("----------");
}
if (!_g1h->is_in_closed_subset(obj)) {
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
gclog_or_tty->print_cr("Field "PTR_FORMAT
" of live obj "PTR_FORMAT" in region "
"["PTR_FORMAT", "PTR_FORMAT")",
p, (void*) _containing_obj,
from->bottom(), from->end());
print_object(gclog_or_tty, _containing_obj);
gclog_or_tty->print_cr("points to obj "PTR_FORMAT" not in the heap",
(void*) obj);
} else {
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj);
gclog_or_tty->print_cr("Field "PTR_FORMAT
" of live obj "PTR_FORMAT" in region "
"["PTR_FORMAT", "PTR_FORMAT")",
p, (void*) _containing_obj,
from->bottom(), from->end());
print_object(gclog_or_tty, _containing_obj);
gclog_or_tty->print_cr("points to dead obj "PTR_FORMAT" in region "
"["PTR_FORMAT", "PTR_FORMAT")",
(void*) obj, to->bottom(), to->end());
print_object(gclog_or_tty, obj);
}
gclog_or_tty->print_cr("----------");
gclog_or_tty->flush();
_failures = true;
failed = true;
_n_failures++;
}
if (!_g1h->full_collection() || G1VerifyRSetsDuringFullGC) {
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
HeapRegion* to = _g1h->heap_region_containing(obj);
if (from != NULL && to != NULL &&
from != to &&
!to->isHumongous()) {
jbyte cv_obj = *_bs->byte_for_const(_containing_obj);
jbyte cv_field = *_bs->byte_for_const(p);
const jbyte dirty = CardTableModRefBS::dirty_card_val();
bool is_bad = !(from->is_young()
|| to->rem_set()->contains_reference(p)
|| !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed
(_containing_obj->is_objArray() ?
cv_field == dirty
: cv_obj == dirty || cv_field == dirty));
if (is_bad) {
MutexLockerEx x(ParGCRareEvent_lock,
Mutex::_no_safepoint_check_flag);
if (!_failures) {
gclog_or_tty->print_cr("");
gclog_or_tty->print_cr("----------");
}
gclog_or_tty->print_cr("Missing rem set entry:");
gclog_or_tty->print_cr("Field "PTR_FORMAT" "
"of obj "PTR_FORMAT", "
"in region "HR_FORMAT,
p, (void*) _containing_obj,
HR_FORMAT_PARAMS(from));
_containing_obj->print_on(gclog_or_tty);
gclog_or_tty->print_cr("points to obj "PTR_FORMAT" "
"in region "HR_FORMAT,
(void*) obj,
HR_FORMAT_PARAMS(to));
obj->print_on(gclog_or_tty);
gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.",
cv_obj, cv_field);
gclog_or_tty->print_cr("----------");
gclog_or_tty->flush();
_failures = true;
if (!failed) _n_failures++;
}
}
}
}
}
};
template<class ClosureType>
HeapWord* walk_mem_region_loop(ClosureType* cl, G1CollectedHeap* g1h,
HeapRegion* hr,
@ -368,7 +231,7 @@ void HeapRegion::hr_clear(bool par, bool clear_space) {
if (!par) {
// If this is parallel, this will be done later.
HeapRegionRemSet* hrrs = rem_set();
if (hrrs != NULL) hrrs->clear();
hrrs->clear();
_claimed = InitialClaimValue;
}
zero_marked_bytes();
@ -505,6 +368,7 @@ HeapRegion::HeapRegion(uint hrs_index,
_rem_set(NULL), _recorded_rs_length(0), _predicted_elapsed_time_ms(0),
_predicted_bytes_to_copy(0)
{
_rem_set = new HeapRegionRemSet(sharedOffsetArray, this);
_orig_end = mr.end();
// Note that initialize() will set the start of the unmarked area of the
// region.
@ -512,8 +376,6 @@ HeapRegion::HeapRegion(uint hrs_index,
set_top(bottom());
set_saved_mark();
_rem_set = new HeapRegionRemSet(sharedOffsetArray, this);
assert(HeapRegionRemSet::num_par_rem_sets() > 0, "Invariant.");
}
@ -733,6 +595,160 @@ oops_on_card_seq_iterate_careful(MemRegion mr,
return NULL;
}
// Code roots support
void HeapRegion::add_strong_code_root(nmethod* nm) {
HeapRegionRemSet* hrrs = rem_set();
hrrs->add_strong_code_root(nm);
}
void HeapRegion::remove_strong_code_root(nmethod* nm) {
HeapRegionRemSet* hrrs = rem_set();
hrrs->remove_strong_code_root(nm);
}
void HeapRegion::migrate_strong_code_roots() {
assert(in_collection_set(), "only collection set regions");
assert(!isHumongous(), "not humongous regions");
HeapRegionRemSet* hrrs = rem_set();
hrrs->migrate_strong_code_roots();
}
void HeapRegion::strong_code_roots_do(CodeBlobClosure* blk) const {
HeapRegionRemSet* hrrs = rem_set();
hrrs->strong_code_roots_do(blk);
}
class VerifyStrongCodeRootOopClosure: public OopClosure {
const HeapRegion* _hr;
nmethod* _nm;
bool _failures;
bool _has_oops_in_region;
template <class T> void do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
// Note: not all the oops embedded in the nmethod are in the
// current region. We only look at those which are.
if (_hr->is_in(obj)) {
// Object is in the region. Check that its less than top
if (_hr->top() <= (HeapWord*)obj) {
// Object is above top
gclog_or_tty->print_cr("Object "PTR_FORMAT" in region "
"["PTR_FORMAT", "PTR_FORMAT") is above "
"top "PTR_FORMAT,
obj, _hr->bottom(), _hr->end(), _hr->top());
_failures = true;
return;
}
// Nmethod has at least one oop in the current region
_has_oops_in_region = true;
}
}
}
public:
VerifyStrongCodeRootOopClosure(const HeapRegion* hr, nmethod* nm):
_hr(hr), _failures(false), _has_oops_in_region(false) {}
void do_oop(narrowOop* p) { do_oop_work(p); }
void do_oop(oop* p) { do_oop_work(p); }
bool failures() { return _failures; }
bool has_oops_in_region() { return _has_oops_in_region; }
};
class VerifyStrongCodeRootCodeBlobClosure: public CodeBlobClosure {
const HeapRegion* _hr;
bool _failures;
public:
VerifyStrongCodeRootCodeBlobClosure(const HeapRegion* hr) :
_hr(hr), _failures(false) {}
void do_code_blob(CodeBlob* cb) {
nmethod* nm = (cb == NULL) ? NULL : cb->as_nmethod_or_null();
if (nm != NULL) {
// Verify that the nemthod is live
if (!nm->is_alive()) {
gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] has dead nmethod "
PTR_FORMAT" in its strong code roots",
_hr->bottom(), _hr->end(), nm);
_failures = true;
} else {
VerifyStrongCodeRootOopClosure oop_cl(_hr, nm);
nm->oops_do(&oop_cl);
if (!oop_cl.has_oops_in_region()) {
gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] has nmethod "
PTR_FORMAT" in its strong code roots "
"with no pointers into region",
_hr->bottom(), _hr->end(), nm);
_failures = true;
} else if (oop_cl.failures()) {
gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] has other "
"failures for nmethod "PTR_FORMAT,
_hr->bottom(), _hr->end(), nm);
_failures = true;
}
}
}
}
bool failures() { return _failures; }
};
void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const {
if (!G1VerifyHeapRegionCodeRoots) {
// We're not verifying code roots.
return;
}
if (vo == VerifyOption_G1UseMarkWord) {
// Marking verification during a full GC is performed after class
// unloading, code cache unloading, etc so the strong code roots
// attached to each heap region are in an inconsistent state. They won't
// be consistent until the strong code roots are rebuilt after the
// actual GC. Skip verifying the strong code roots in this particular
// time.
assert(VerifyDuringGC, "only way to get here");
return;
}
HeapRegionRemSet* hrrs = rem_set();
int strong_code_roots_length = hrrs->strong_code_roots_list_length();
// if this region is empty then there should be no entries
// on its strong code root list
if (is_empty()) {
if (strong_code_roots_length > 0) {
gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is empty "
"but has "INT32_FORMAT" code root entries",
bottom(), end(), strong_code_roots_length);
*failures = true;
}
return;
}
// An H-region should have an empty strong code root list
if (isHumongous()) {
if (strong_code_roots_length > 0) {
gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is humongous "
"but has "INT32_FORMAT" code root entries",
bottom(), end(), strong_code_roots_length);
*failures = true;
}
return;
}
VerifyStrongCodeRootCodeBlobClosure cb_cl(this);
strong_code_roots_do(&cb_cl);
if (cb_cl.failures()) {
*failures = true;
}
}
void HeapRegion::print() const { print_on(gclog_or_tty); }
void HeapRegion::print_on(outputStream* st) const {
if (isHumongous()) {
@ -761,10 +777,143 @@ void HeapRegion::print_on(outputStream* st) const {
G1OffsetTableContigSpace::print_on(st);
}
void HeapRegion::verify() const {
bool dummy = false;
verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy);
}
class VerifyLiveClosure: public OopClosure {
private:
G1CollectedHeap* _g1h;
CardTableModRefBS* _bs;
oop _containing_obj;
bool _failures;
int _n_failures;
VerifyOption _vo;
public:
// _vo == UsePrevMarking -> use "prev" marking information,
// _vo == UseNextMarking -> use "next" marking information,
// _vo == UseMarkWord -> use mark word from object header.
VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) :
_g1h(g1h), _bs(NULL), _containing_obj(NULL),
_failures(false), _n_failures(0), _vo(vo)
{
BarrierSet* bs = _g1h->barrier_set();
if (bs->is_a(BarrierSet::CardTableModRef))
_bs = (CardTableModRefBS*)bs;
}
void set_containing_obj(oop obj) {
_containing_obj = obj;
}
bool failures() { return _failures; }
int n_failures() { return _n_failures; }
virtual void do_oop(narrowOop* p) { do_oop_work(p); }
virtual void do_oop( oop* p) { do_oop_work(p); }
void print_object(outputStream* out, oop obj) {
#ifdef PRODUCT
Klass* k = obj->klass();
const char* class_name = InstanceKlass::cast(k)->external_name();
out->print_cr("class name %s", class_name);
#else // PRODUCT
obj->print_on(out);
#endif // PRODUCT
}
template <class T>
void do_oop_work(T* p) {
assert(_containing_obj != NULL, "Precondition");
assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo),
"Precondition");
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
bool failed = false;
if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) {
MutexLockerEx x(ParGCRareEvent_lock,
Mutex::_no_safepoint_check_flag);
if (!_failures) {
gclog_or_tty->print_cr("");
gclog_or_tty->print_cr("----------");
}
if (!_g1h->is_in_closed_subset(obj)) {
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
gclog_or_tty->print_cr("Field "PTR_FORMAT
" of live obj "PTR_FORMAT" in region "
"["PTR_FORMAT", "PTR_FORMAT")",
p, (void*) _containing_obj,
from->bottom(), from->end());
print_object(gclog_or_tty, _containing_obj);
gclog_or_tty->print_cr("points to obj "PTR_FORMAT" not in the heap",
(void*) obj);
} else {
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj);
gclog_or_tty->print_cr("Field "PTR_FORMAT
" of live obj "PTR_FORMAT" in region "
"["PTR_FORMAT", "PTR_FORMAT")",
p, (void*) _containing_obj,
from->bottom(), from->end());
print_object(gclog_or_tty, _containing_obj);
gclog_or_tty->print_cr("points to dead obj "PTR_FORMAT" in region "
"["PTR_FORMAT", "PTR_FORMAT")",
(void*) obj, to->bottom(), to->end());
print_object(gclog_or_tty, obj);
}
gclog_or_tty->print_cr("----------");
gclog_or_tty->flush();
_failures = true;
failed = true;
_n_failures++;
}
if (!_g1h->full_collection() || G1VerifyRSetsDuringFullGC) {
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
HeapRegion* to = _g1h->heap_region_containing(obj);
if (from != NULL && to != NULL &&
from != to &&
!to->isHumongous()) {
jbyte cv_obj = *_bs->byte_for_const(_containing_obj);
jbyte cv_field = *_bs->byte_for_const(p);
const jbyte dirty = CardTableModRefBS::dirty_card_val();
bool is_bad = !(from->is_young()
|| to->rem_set()->contains_reference(p)
|| !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed
(_containing_obj->is_objArray() ?
cv_field == dirty
: cv_obj == dirty || cv_field == dirty));
if (is_bad) {
MutexLockerEx x(ParGCRareEvent_lock,
Mutex::_no_safepoint_check_flag);
if (!_failures) {
gclog_or_tty->print_cr("");
gclog_or_tty->print_cr("----------");
}
gclog_or_tty->print_cr("Missing rem set entry:");
gclog_or_tty->print_cr("Field "PTR_FORMAT" "
"of obj "PTR_FORMAT", "
"in region "HR_FORMAT,
p, (void*) _containing_obj,
HR_FORMAT_PARAMS(from));
_containing_obj->print_on(gclog_or_tty);
gclog_or_tty->print_cr("points to obj "PTR_FORMAT" "
"in region "HR_FORMAT,
(void*) obj,
HR_FORMAT_PARAMS(to));
obj->print_on(gclog_or_tty);
gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.",
cv_obj, cv_field);
gclog_or_tty->print_cr("----------");
gclog_or_tty->flush();
_failures = true;
if (!failed) _n_failures++;
}
}
}
}
}
};
// This really ought to be commoned up into OffsetTableContigSpace somehow.
// We would need a mechanism to make that code skip dead objects.
@ -904,6 +1053,13 @@ void HeapRegion::verify(VerifyOption vo,
*failures = true;
return;
}
verify_strong_code_roots(vo, failures);
}
void HeapRegion::verify() const {
bool dummy = false;
verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy);
}
// G1OffsetTableContigSpace code; copied from space.cpp. Hope this can go

View File

@ -52,6 +52,7 @@ class HeapRegionRemSet;
class HeapRegionRemSetIterator;
class HeapRegion;
class HeapRegionSetBase;
class nmethod;
#define HR_FORMAT "%u:(%s)["PTR_FORMAT","PTR_FORMAT","PTR_FORMAT"]"
#define HR_FORMAT_PARAMS(_hr_) \
@ -371,7 +372,8 @@ class HeapRegion: public G1OffsetTableContigSpace {
RebuildRSClaimValue = 5,
ParEvacFailureClaimValue = 6,
AggregateCountClaimValue = 7,
VerifyCountClaimValue = 8
VerifyCountClaimValue = 8,
ParMarkRootClaimValue = 9
};
inline HeapWord* par_allocate_no_bot_updates(size_t word_size) {
@ -796,6 +798,25 @@ class HeapRegion: public G1OffsetTableContigSpace {
virtual void reset_after_compaction();
// Routines for managing a list of code roots (attached to the
// this region's RSet) that point into this heap region.
void add_strong_code_root(nmethod* nm);
void remove_strong_code_root(nmethod* nm);
// During a collection, migrate the successfully evacuated
// strong code roots that referenced into this region to the
// new regions that they now point into. Unsuccessfully
// evacuated code roots are not migrated.
void migrate_strong_code_roots();
// Applies blk->do_code_blob() to each of the entries in
// the strong code roots list for this region
void strong_code_roots_do(CodeBlobClosure* blk) const;
// Verify that the entries on the strong code root list for this
// region are live and include at least one pointer into this region.
void verify_strong_code_roots(VerifyOption vo, bool* failures) const;
void print() const;
void print_on(outputStream* st) const;

View File

@ -33,6 +33,7 @@
#include "oops/oop.inline.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
class PerRegionTable: public CHeapObj<mtGC> {
friend class OtherRegionsTable;
@ -849,7 +850,7 @@ int HeapRegionRemSet::num_par_rem_sets() {
HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
HeapRegion* hr)
: _bosa(bosa), _other_regions(hr) {
: _bosa(bosa), _strong_code_roots_list(NULL), _other_regions(hr) {
reset_for_par_iteration();
}
@ -908,6 +909,12 @@ void HeapRegionRemSet::cleanup() {
}
void HeapRegionRemSet::clear() {
if (_strong_code_roots_list != NULL) {
delete _strong_code_roots_list;
}
_strong_code_roots_list = new (ResourceObj::C_HEAP, mtGC)
GrowableArray<nmethod*>(10, 0, NULL, true);
_other_regions.clear();
assert(occupied() == 0, "Should be clear.");
reset_for_par_iteration();
@ -925,6 +932,121 @@ void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs,
_other_regions.scrub(ctbs, region_bm, card_bm);
}
// Code roots support
void HeapRegionRemSet::add_strong_code_root(nmethod* nm) {
assert(nm != NULL, "sanity");
// Search for the code blob from the RHS to avoid
// duplicate entries as much as possible
if (_strong_code_roots_list->find_from_end(nm) < 0) {
// Code blob isn't already in the list
_strong_code_roots_list->push(nm);
}
}
void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) {
assert(nm != NULL, "sanity");
int idx = _strong_code_roots_list->find(nm);
if (idx >= 0) {
_strong_code_roots_list->remove_at(idx);
}
// Check that there were no duplicates
guarantee(_strong_code_roots_list->find(nm) < 0, "duplicate entry found");
}
class NMethodMigrationOopClosure : public OopClosure {
G1CollectedHeap* _g1h;
HeapRegion* _from;
nmethod* _nm;
uint _num_self_forwarded;
template <class T> void do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (_from->is_in(obj)) {
// Reference still points into the source region.
// Since roots are immediately evacuated this means that
// we must have self forwarded the object
assert(obj->is_forwarded(),
err_msg("code roots should be immediately evacuated. "
"Ref: "PTR_FORMAT", "
"Obj: "PTR_FORMAT", "
"Region: "HR_FORMAT,
p, (void*) obj, HR_FORMAT_PARAMS(_from)));
assert(obj->forwardee() == obj,
err_msg("not self forwarded? obj = "PTR_FORMAT, (void*)obj));
// The object has been self forwarded.
// Note, if we're during an initial mark pause, there is
// no need to explicitly mark object. It will be marked
// during the regular evacuation failure handling code.
_num_self_forwarded++;
} else {
// The reference points into a promotion or to-space region
HeapRegion* to = _g1h->heap_region_containing(obj);
to->rem_set()->add_strong_code_root(_nm);
}
}
}
public:
NMethodMigrationOopClosure(G1CollectedHeap* g1h, HeapRegion* from, nmethod* nm):
_g1h(g1h), _from(from), _nm(nm), _num_self_forwarded(0) {}
void do_oop(narrowOop* p) { do_oop_work(p); }
void do_oop(oop* p) { do_oop_work(p); }
uint retain() { return _num_self_forwarded > 0; }
};
void HeapRegionRemSet::migrate_strong_code_roots() {
assert(hr()->in_collection_set(), "only collection set regions");
assert(!hr()->isHumongous(), "not humongous regions");
ResourceMark rm;
// List of code blobs to retain for this region
GrowableArray<nmethod*> to_be_retained(10);
G1CollectedHeap* g1h = G1CollectedHeap::heap();
while (_strong_code_roots_list->is_nonempty()) {
nmethod *nm = _strong_code_roots_list->pop();
if (nm != NULL) {
NMethodMigrationOopClosure oop_cl(g1h, hr(), nm);
nm->oops_do(&oop_cl);
if (oop_cl.retain()) {
to_be_retained.push(nm);
}
}
}
// Now push any code roots we need to retain
assert(to_be_retained.is_empty() || hr()->evacuation_failed(),
"Retained nmethod list must be empty or "
"evacuation of this region failed");
while (to_be_retained.is_nonempty()) {
nmethod* nm = to_be_retained.pop();
assert(nm != NULL, "sanity");
add_strong_code_root(nm);
}
}
void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const {
for (int i = 0; i < _strong_code_roots_list->length(); i += 1) {
nmethod* nm = _strong_code_roots_list->at(i);
blk->do_code_blob(nm);
}
}
size_t HeapRegionRemSet::strong_code_roots_mem_size() {
return sizeof(GrowableArray<nmethod*>) +
_strong_code_roots_list->max_length() * sizeof(nmethod*);
}
//-------------------- Iteration --------------------
HeapRegionRemSetIterator:: HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs) :

View File

@ -37,6 +37,7 @@ class HeapRegion;
class HeapRegionRemSetIterator;
class PerRegionTable;
class SparsePRT;
class nmethod;
// Essentially a wrapper around SparsePRTCleanupTask. See
// sparsePRT.hpp for more details.
@ -191,6 +192,10 @@ private:
G1BlockOffsetSharedArray* _bosa;
G1BlockOffsetSharedArray* bosa() const { return _bosa; }
// A list of code blobs (nmethods) whose code contains pointers into
// the region that owns this RSet.
GrowableArray<nmethod*>* _strong_code_roots_list;
OtherRegionsTable _other_regions;
enum ParIterState { Unclaimed, Claimed, Complete };
@ -282,11 +287,13 @@ public:
}
// The actual # of bytes this hr_remset takes up.
// Note also includes the strong code root set.
size_t mem_size() {
return _other_regions.mem_size()
// This correction is necessary because the above includes the second
// part.
+ sizeof(this) - sizeof(OtherRegionsTable);
+ (sizeof(this) - sizeof(OtherRegionsTable))
+ strong_code_roots_mem_size();
}
// Returns the memory occupancy of all static data structures associated
@ -304,6 +311,37 @@ public:
bool contains_reference(OopOrNarrowOopStar from) const {
return _other_regions.contains_reference(from);
}
// Routines for managing the list of code roots that point into
// the heap region that owns this RSet.
void add_strong_code_root(nmethod* nm);
void remove_strong_code_root(nmethod* nm);
// During a collection, migrate the successfully evacuated strong
// code roots that referenced into the region that owns this RSet
// to the RSets of the new regions that they now point into.
// Unsuccessfully evacuated code roots are not migrated.
void migrate_strong_code_roots();
// Applies blk->do_code_blob() to each of the entries in
// the strong code roots list
void strong_code_roots_do(CodeBlobClosure* blk) const;
// Returns the number of elements in the strong code roots list
int strong_code_roots_list_length() {
return _strong_code_roots_list->length();
}
// Returns true if the strong code roots contains the given
// nmethod.
bool strong_code_roots_list_contains(nmethod* nm) {
return _strong_code_roots_list->contains(nm);
}
// Returns the amount of memory, in bytes, currently
// consumed by the strong code roots.
size_t strong_code_roots_mem_size();
void print() const;
// Called during a stop-world phase to perform any deferred cleanups.

View File

@ -70,9 +70,6 @@ VM_G1IncCollectionPause::VM_G1IncCollectionPause(
guarantee(target_pause_time_ms > 0.0,
err_msg("target_pause_time_ms = %1.6lf should be positive",
target_pause_time_ms));
guarantee(word_size == 0 || gc_cause == GCCause::_g1_inc_collection_pause,
"we can only request an allocation if the GC cause is for "
"an incremental GC pause");
_gc_cause = gc_cause;
}

View File

@ -216,6 +216,7 @@ void ParallelScavengeHeap::update_counters() {
young_gen()->update_counters();
old_gen()->update_counters();
MetaspaceCounters::update_performance_counters();
CompressedClassSpaceCounters::update_performance_counters();
}
size_t ParallelScavengeHeap::capacity() const {

View File

@ -118,6 +118,14 @@ void CollectedHeap::print_heap_after_gc() {
}
}
void CollectedHeap::register_nmethod(nmethod* nm) {
assert_locked_or_safepoint(CodeCache_lock);
}
void CollectedHeap::unregister_nmethod(nmethod* nm) {
assert_locked_or_safepoint(CodeCache_lock);
}
void CollectedHeap::trace_heap(GCWhen::Type when, GCTracer* gc_tracer) {
const GCHeapSummary& heap_summary = create_heap_summary();
const MetaspaceSummary& metaspace_summary = create_metaspace_summary();

View File

@ -49,6 +49,7 @@ class MetaspaceSummary;
class Thread;
class ThreadClosure;
class VirtualSpaceSummary;
class nmethod;
class GCMessage : public FormatBuffer<1024> {
public:
@ -603,6 +604,11 @@ class CollectedHeap : public CHeapObj<mtInternal> {
void print_heap_before_gc();
void print_heap_after_gc();
// Registering and unregistering an nmethod (compiled code) with the heap.
// Override with specific mechanism for each specialized heap type.
virtual void register_nmethod(nmethod* nm);
virtual void unregister_nmethod(nmethod* nm);
void trace_heap_before_gc(GCTracer* gc_tracer);
void trace_heap_after_gc(GCTracer* gc_tracer);

View File

@ -666,7 +666,7 @@ class ResourceObj ALLOCATION_SUPER_CLASS_SPEC {
NEW_RESOURCE_ARRAY_RETURN_NULL(type, 1)
#define NEW_C_HEAP_ARRAY3(type, size, memflags, pc, allocfail)\
(type*) AllocateHeap(size * sizeof(type), memflags, pc, allocfail)
(type*) AllocateHeap((size) * sizeof(type), memflags, pc, allocfail)
#define NEW_C_HEAP_ARRAY2(type, size, memflags, pc)\
(type*) (AllocateHeap((size) * sizeof(type), memflags, pc))
@ -675,16 +675,16 @@ class ResourceObj ALLOCATION_SUPER_CLASS_SPEC {
(type*) (AllocateHeap((size) * sizeof(type), memflags))
#define NEW_C_HEAP_ARRAY2_RETURN_NULL(type, size, memflags, pc)\
NEW_C_HEAP_ARRAY3(type, size, memflags, pc, AllocFailStrategy::RETURN_NULL)
NEW_C_HEAP_ARRAY3(type, (size), memflags, pc, AllocFailStrategy::RETURN_NULL)
#define NEW_C_HEAP_ARRAY_RETURN_NULL(type, size, memflags)\
NEW_C_HEAP_ARRAY3(type, size, memflags, (address)0, AllocFailStrategy::RETURN_NULL)
NEW_C_HEAP_ARRAY3(type, (size), memflags, (address)0, AllocFailStrategy::RETURN_NULL)
#define REALLOC_C_HEAP_ARRAY(type, old, size, memflags)\
(type*) (ReallocateHeap((char*)old, (size) * sizeof(type), memflags))
(type*) (ReallocateHeap((char*)(old), (size) * sizeof(type), memflags))
#define REALLOC_C_HEAP_ARRAY_RETURN_NULL(type, old, size, memflags)\
(type*) (ReallocateHeap((char*)old, (size) * sizeof(type), memflags, AllocFailStrategy::RETURN_NULL))
(type*) (ReallocateHeap((char*)(old), (size) * sizeof(type), memflags, AllocFailStrategy::RETURN_NULL))
#define FREE_C_HEAP_ARRAY(type, old, memflags) \
FreeHeap((char*)(old), memflags)

View File

@ -193,6 +193,8 @@ size_t GenCollectorPolicy::compute_max_alignment() {
alignment = lcm(os::large_page_size(), alignment);
}
assert(alignment >= min_alignment(), "Must be");
return alignment;
}

View File

@ -362,15 +362,12 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() {
ReservedSpace FileMapInfo::reserve_shared_memory() {
struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[0];
char* requested_addr = si->_base;
size_t alignment = os::vm_allocation_granularity();
size_t size = align_size_up(SharedReadOnlySize + SharedReadWriteSize +
SharedMiscDataSize + SharedMiscCodeSize,
alignment);
size_t size = FileMapInfo::shared_spaces_size();
// Reserve the space first, then map otherwise map will go right over some
// other reserved memory (like the code cache).
ReservedSpace rs(size, alignment, false, requested_addr);
ReservedSpace rs(size, os::vm_allocation_granularity(), false, requested_addr);
if (!rs.is_reserved()) {
fail_continue(err_msg("Unable to reserve shared space at required address " INTPTR_FORMAT, requested_addr));
return rs;
@ -559,3 +556,19 @@ void FileMapInfo::print_shared_spaces() {
si->_base, si->_base + si->_used);
}
}
// Unmap mapped regions of shared space.
void FileMapInfo::stop_sharing_and_unmap(const char* msg) {
FileMapInfo *map_info = FileMapInfo::current_info();
if (map_info) {
map_info->fail_continue(msg);
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
if (map_info->_header._space[i]._base != NULL) {
map_info->unmap_region(i);
map_info->_header._space[i]._base = NULL;
}
}
} else if (DumpSharedSpaces) {
fail_stop(msg, NULL);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -150,6 +150,15 @@ public:
// Return true if given address is in the mapped shared space.
bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false);
void print_shared_spaces() NOT_CDS_RETURN;
static size_t shared_spaces_size() {
return align_size_up(SharedReadOnlySize + SharedReadWriteSize +
SharedMiscDataSize + SharedMiscCodeSize,
os::vm_allocation_granularity());
}
// Stop CDS sharing and unmap CDS regions.
static void stop_sharing_and_unmap(const char* msg);
};
#endif // SHARE_VM_MEMORY_FILEMAP_HPP

View File

@ -95,13 +95,13 @@ jint GenCollectedHeap::initialize() {
guarantee(HeapWordSize == wordSize, "HeapWordSize must equal wordSize");
// The heap must be at least as aligned as generations.
size_t alignment = Generation::GenGrain;
size_t gen_alignment = Generation::GenGrain;
_gen_specs = gen_policy()->generations();
// Make sure the sizes are all aligned.
for (i = 0; i < _n_gens; i++) {
_gen_specs[i]->align(alignment);
_gen_specs[i]->align(gen_alignment);
}
// Allocate space for the heap.
@ -109,9 +109,11 @@ jint GenCollectedHeap::initialize() {
char* heap_address;
size_t total_reserved = 0;
int n_covered_regions = 0;
ReservedSpace heap_rs(0);
ReservedSpace heap_rs;
heap_address = allocate(alignment, &total_reserved,
size_t heap_alignment = collector_policy()->max_alignment();
heap_address = allocate(heap_alignment, &total_reserved,
&n_covered_regions, &heap_rs);
if (!heap_rs.is_reserved()) {
@ -168,6 +170,8 @@ char* GenCollectedHeap::allocate(size_t alignment,
const size_t pageSize = UseLargePages ?
os::large_page_size() : os::vm_page_size();
assert(alignment % pageSize == 0, "Must be");
for (int i = 0; i < _n_gens; i++) {
total_reserved += _gen_specs[i]->max_size();
if (total_reserved < _gen_specs[i]->max_size()) {
@ -175,24 +179,17 @@ char* GenCollectedHeap::allocate(size_t alignment,
}
n_covered_regions += _gen_specs[i]->n_covered_regions();
}
assert(total_reserved % pageSize == 0,
err_msg("Gen size; total_reserved=" SIZE_FORMAT ", pageSize="
SIZE_FORMAT, total_reserved, pageSize));
assert(total_reserved % alignment == 0,
err_msg("Gen size; total_reserved=" SIZE_FORMAT ", alignment="
SIZE_FORMAT, total_reserved, alignment));
// Needed until the cardtable is fixed to have the right number
// of covered regions.
n_covered_regions += 2;
if (UseLargePages) {
assert(total_reserved != 0, "total_reserved cannot be 0");
total_reserved = round_to(total_reserved, os::large_page_size());
if (total_reserved < os::large_page_size()) {
vm_exit_during_initialization(overflow_msg);
}
}
*_total_reserved = total_reserved;
*_n_covered_regions = n_covered_regions;
*_total_reserved = total_reserved;
*_n_covered_regions = n_covered_regions;
*heap_rs = Universe::reserve_heap(total_reserved, alignment);
return heap_rs->base();
}
@ -1211,6 +1208,7 @@ void GenCollectedHeap::gc_epilogue(bool full) {
}
MetaspaceCounters::update_performance_counters();
CompressedClassSpaceCounters::update_performance_counters();
always_do_update_barrier = UseConcMarkSweepGC;
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -118,9 +118,12 @@ bool CodeHeap::reserve(size_t reserved_size, size_t committed_size,
_number_of_committed_segments = size_to_segments(_memory.committed_size());
_number_of_reserved_segments = size_to_segments(_memory.reserved_size());
assert(_number_of_reserved_segments >= _number_of_committed_segments, "just checking");
const size_t reserved_segments_alignment = MAX2((size_t)os::vm_page_size(), granularity);
const size_t reserved_segments_size = align_size_up(_number_of_reserved_segments, reserved_segments_alignment);
const size_t committed_segments_size = align_to_page_size(_number_of_committed_segments);
// reserve space for _segmap
if (!_segmap.initialize(align_to_page_size(_number_of_reserved_segments), align_to_page_size(_number_of_committed_segments))) {
if (!_segmap.initialize(reserved_segments_size, committed_segments_size)) {
return false;
}

View File

@ -64,7 +64,7 @@ void MarkingCodeBlobClosure::do_code_blob(CodeBlob* cb) {
}
void CodeBlobToOopClosure::do_newly_marked_nmethod(nmethod* nm) {
nm->oops_do(_cl, /*do_strong_roots_only=*/ true);
nm->oops_do(_cl, /*allow_zombie=*/ false);
}
void CodeBlobToOopClosure::do_code_blob(CodeBlob* cb) {

View File

@ -35,6 +35,7 @@
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "runtime/globals.hpp"
#include "runtime/java.hpp"
#include "runtime/mutex.hpp"
#include "runtime/orderAccess.hpp"
#include "services/memTracker.hpp"
@ -54,6 +55,8 @@ size_t const allocation_from_dictionary_limit = 64 * K;
MetaWord* last_allocated = 0;
size_t Metaspace::_class_metaspace_size;
// Used in declarations in SpaceManager and ChunkManager
enum ChunkIndex {
ZeroIndex = 0,
@ -261,10 +264,6 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
// count of chunks contained in this VirtualSpace
uintx _container_count;
// Convenience functions for logical bottom and end
MetaWord* bottom() const { return (MetaWord*) _virtual_space.low(); }
MetaWord* end() const { return (MetaWord*) _virtual_space.high(); }
// Convenience functions to access the _virtual_space
char* low() const { return virtual_space()->low(); }
char* high() const { return virtual_space()->high(); }
@ -284,6 +283,10 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
VirtualSpaceNode(ReservedSpace rs) : _top(NULL), _next(NULL), _rs(rs), _container_count(0) {}
~VirtualSpaceNode();
// Convenience functions for logical bottom and end
MetaWord* bottom() const { return (MetaWord*) _virtual_space.low(); }
MetaWord* end() const { return (MetaWord*) _virtual_space.high(); }
// address of next available space in _virtual_space;
// Accessors
VirtualSpaceNode* next() { return _next; }
@ -342,7 +345,7 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
};
// byte_size is the size of the associated virtualspace.
VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0), _container_count(0) {
VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(), _container_count(0) {
// align up to vm allocation granularity
byte_size = align_size_up(byte_size, os::vm_allocation_granularity());
@ -1313,7 +1316,8 @@ bool MetaspaceGC::should_expand(VirtualSpaceList* vsl, size_t word_size) {
// Class virtual space should always be expanded. Call GC for the other
// metadata virtual space.
if (vsl == Metaspace::class_space_list()) return true;
if (Metaspace::using_class_space() &&
(vsl == Metaspace::class_space_list())) return true;
// If this is part of an allocation after a GC, expand
// unconditionally.
@ -2257,7 +2261,7 @@ void SpaceManager::deallocate(MetaWord* p, size_t word_size) {
size_t raw_word_size = get_raw_word_size(word_size);
size_t min_size = TreeChunk<Metablock, FreeList>::min_size();
assert(raw_word_size >= min_size,
err_msg("Should not deallocate dark matter " SIZE_FORMAT, word_size));
err_msg("Should not deallocate dark matter " SIZE_FORMAT "<" SIZE_FORMAT, word_size, min_size));
block_freelists()->return_block(p, raw_word_size);
}
@ -2374,7 +2378,7 @@ MetaWord* SpaceManager::allocate_work(size_t word_size) {
if (result == NULL) {
result = grow_and_allocate(word_size);
}
if (result > 0) {
if (result != 0) {
inc_used_metrics(word_size);
assert(result != (MetaWord*) chunks_in_use(MediumIndex),
"Head of the list is being allocated");
@ -2476,15 +2480,13 @@ void SpaceManager::mangle_freed_chunks() {
size_t MetaspaceAux::_allocated_capacity_words[] = {0, 0};
size_t MetaspaceAux::_allocated_used_words[] = {0, 0};
size_t MetaspaceAux::free_bytes(Metaspace::MetadataType mdtype) {
VirtualSpaceList* list = Metaspace::get_space_list(mdtype);
return list == NULL ? 0 : list->free_bytes();
}
size_t MetaspaceAux::free_bytes() {
size_t result = 0;
if (Metaspace::class_space_list() != NULL) {
result = result + Metaspace::class_space_list()->free_bytes();
}
if (Metaspace::space_list() != NULL) {
result = result + Metaspace::space_list()->free_bytes();
}
return result;
return free_bytes(Metaspace::ClassType) + free_bytes(Metaspace::NonClassType);
}
void MetaspaceAux::dec_capacity(Metaspace::MetadataType mdtype, size_t words) {
@ -2549,6 +2551,9 @@ size_t MetaspaceAux::free_in_bytes(Metaspace::MetadataType mdtype) {
}
size_t MetaspaceAux::capacity_bytes_slow(Metaspace::MetadataType mdtype) {
if ((mdtype == Metaspace::ClassType) && !Metaspace::using_class_space()) {
return 0;
}
// Don't count the space in the freelists. That space will be
// added to the capacity calculation as needed.
size_t capacity = 0;
@ -2563,18 +2568,18 @@ size_t MetaspaceAux::capacity_bytes_slow(Metaspace::MetadataType mdtype) {
}
size_t MetaspaceAux::reserved_in_bytes(Metaspace::MetadataType mdtype) {
size_t reserved = (mdtype == Metaspace::ClassType) ?
Metaspace::class_space_list()->virtual_space_total() :
Metaspace::space_list()->virtual_space_total();
return reserved * BytesPerWord;
VirtualSpaceList* list = Metaspace::get_space_list(mdtype);
return list == NULL ? 0 : list->virtual_space_total();
}
size_t MetaspaceAux::min_chunk_size() { return Metaspace::first_chunk_word_size(); }
size_t MetaspaceAux::free_chunks_total(Metaspace::MetadataType mdtype) {
ChunkManager* chunk = (mdtype == Metaspace::ClassType) ?
Metaspace::class_space_list()->chunk_manager() :
Metaspace::space_list()->chunk_manager();
VirtualSpaceList* list = Metaspace::get_space_list(mdtype);
if (list == NULL) {
return 0;
}
ChunkManager* chunk = list->chunk_manager();
chunk->slow_verify();
return chunk->free_chunks_total();
}
@ -2615,7 +2620,6 @@ void MetaspaceAux::print_metaspace_change(size_t prev_metadata_used) {
// This is printed when PrintGCDetails
void MetaspaceAux::print_on(outputStream* out) {
Metaspace::MetadataType ct = Metaspace::ClassType;
Metaspace::MetadataType nct = Metaspace::NonClassType;
out->print_cr(" Metaspace total "
@ -2629,12 +2633,15 @@ void MetaspaceAux::print_on(outputStream* out) {
allocated_capacity_bytes(nct)/K,
allocated_used_bytes(nct)/K,
reserved_in_bytes(nct)/K);
out->print_cr(" class space "
SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
" reserved " SIZE_FORMAT "K",
allocated_capacity_bytes(ct)/K,
allocated_used_bytes(ct)/K,
reserved_in_bytes(ct)/K);
if (Metaspace::using_class_space()) {
Metaspace::MetadataType ct = Metaspace::ClassType;
out->print_cr(" class space "
SIZE_FORMAT "K, used " SIZE_FORMAT "K,"
" reserved " SIZE_FORMAT "K",
allocated_capacity_bytes(ct)/K,
allocated_used_bytes(ct)/K,
reserved_in_bytes(ct)/K);
}
}
// Print information for class space and data space separately.
@ -2659,13 +2666,37 @@ void MetaspaceAux::print_on(outputStream* out, Metaspace::MetadataType mdtype) {
assert(!SafepointSynchronize::is_at_safepoint() || used_and_free == capacity_bytes, "Accounting is wrong");
}
// Print total fragmentation for class and data metaspaces separately
void MetaspaceAux::print_waste(outputStream* out) {
size_t specialized_waste = 0, small_waste = 0, medium_waste = 0;
size_t specialized_count = 0, small_count = 0, medium_count = 0, humongous_count = 0;
// Print total fragmentation for class metaspaces
void MetaspaceAux::print_class_waste(outputStream* out) {
assert(Metaspace::using_class_space(), "class metaspace not used");
size_t cls_specialized_waste = 0, cls_small_waste = 0, cls_medium_waste = 0;
size_t cls_specialized_count = 0, cls_small_count = 0, cls_medium_count = 0, cls_humongous_count = 0;
ClassLoaderDataGraphMetaspaceIterator iter;
while (iter.repeat()) {
Metaspace* msp = iter.get_next();
if (msp != NULL) {
cls_specialized_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SpecializedIndex);
cls_specialized_count += msp->class_vsm()->sum_count_in_chunks_in_use(SpecializedIndex);
cls_small_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SmallIndex);
cls_small_count += msp->class_vsm()->sum_count_in_chunks_in_use(SmallIndex);
cls_medium_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(MediumIndex);
cls_medium_count += msp->class_vsm()->sum_count_in_chunks_in_use(MediumIndex);
cls_humongous_count += msp->class_vsm()->sum_count_in_chunks_in_use(HumongousIndex);
}
}
out->print_cr(" class: " SIZE_FORMAT " specialized(s) " SIZE_FORMAT ", "
SIZE_FORMAT " small(s) " SIZE_FORMAT ", "
SIZE_FORMAT " medium(s) " SIZE_FORMAT ", "
"large count " SIZE_FORMAT,
cls_specialized_count, cls_specialized_waste,
cls_small_count, cls_small_waste,
cls_medium_count, cls_medium_waste, cls_humongous_count);
}
// Print total fragmentation for data and class metaspaces separately
void MetaspaceAux::print_waste(outputStream* out) {
size_t specialized_waste = 0, small_waste = 0, medium_waste = 0;
size_t specialized_count = 0, small_count = 0, medium_count = 0, humongous_count = 0;
ClassLoaderDataGraphMetaspaceIterator iter;
while (iter.repeat()) {
@ -2678,14 +2709,6 @@ void MetaspaceAux::print_waste(outputStream* out) {
medium_waste += msp->vsm()->sum_waste_in_chunks_in_use(MediumIndex);
medium_count += msp->vsm()->sum_count_in_chunks_in_use(MediumIndex);
humongous_count += msp->vsm()->sum_count_in_chunks_in_use(HumongousIndex);
cls_specialized_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SpecializedIndex);
cls_specialized_count += msp->class_vsm()->sum_count_in_chunks_in_use(SpecializedIndex);
cls_small_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SmallIndex);
cls_small_count += msp->class_vsm()->sum_count_in_chunks_in_use(SmallIndex);
cls_medium_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(MediumIndex);
cls_medium_count += msp->class_vsm()->sum_count_in_chunks_in_use(MediumIndex);
cls_humongous_count += msp->class_vsm()->sum_count_in_chunks_in_use(HumongousIndex);
}
}
out->print_cr("Total fragmentation waste (words) doesn't count free space");
@ -2695,13 +2718,9 @@ void MetaspaceAux::print_waste(outputStream* out) {
"large count " SIZE_FORMAT,
specialized_count, specialized_waste, small_count,
small_waste, medium_count, medium_waste, humongous_count);
out->print_cr(" class: " SIZE_FORMAT " specialized(s) " SIZE_FORMAT ", "
SIZE_FORMAT " small(s) " SIZE_FORMAT ", "
SIZE_FORMAT " medium(s) " SIZE_FORMAT ", "
"large count " SIZE_FORMAT,
cls_specialized_count, cls_specialized_waste,
cls_small_count, cls_small_waste,
cls_medium_count, cls_medium_waste, cls_humongous_count);
if (Metaspace::using_class_space()) {
print_class_waste(out);
}
}
// Dump global metaspace things from the end of ClassLoaderDataGraph
@ -2714,7 +2733,9 @@ void MetaspaceAux::dump(outputStream* out) {
void MetaspaceAux::verify_free_chunks() {
Metaspace::space_list()->chunk_manager()->verify();
Metaspace::class_space_list()->chunk_manager()->verify();
if (Metaspace::using_class_space()) {
Metaspace::class_space_list()->chunk_manager()->verify();
}
}
void MetaspaceAux::verify_capacity() {
@ -2776,7 +2797,9 @@ Metaspace::Metaspace(Mutex* lock, MetaspaceType type) {
Metaspace::~Metaspace() {
delete _vsm;
delete _class_vsm;
if (using_class_space()) {
delete _class_vsm;
}
}
VirtualSpaceList* Metaspace::_space_list = NULL;
@ -2784,9 +2807,123 @@ VirtualSpaceList* Metaspace::_class_space_list = NULL;
#define VIRTUALSPACEMULTIPLIER 2
#ifdef _LP64
void Metaspace::set_narrow_klass_base_and_shift(address metaspace_base, address cds_base) {
// Figure out the narrow_klass_base and the narrow_klass_shift. The
// narrow_klass_base is the lower of the metaspace base and the cds base
// (if cds is enabled). The narrow_klass_shift depends on the distance
// between the lower base and higher address.
address lower_base;
address higher_address;
if (UseSharedSpaces) {
higher_address = MAX2((address)(cds_base + FileMapInfo::shared_spaces_size()),
(address)(metaspace_base + class_metaspace_size()));
lower_base = MIN2(metaspace_base, cds_base);
} else {
higher_address = metaspace_base + class_metaspace_size();
lower_base = metaspace_base;
}
Universe::set_narrow_klass_base(lower_base);
if ((uint64_t)(higher_address - lower_base) < (uint64_t)max_juint) {
Universe::set_narrow_klass_shift(0);
} else {
assert(!UseSharedSpaces, "Cannot shift with UseSharedSpaces");
Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes);
}
}
// Return TRUE if the specified metaspace_base and cds_base are close enough
// to work with compressed klass pointers.
bool Metaspace::can_use_cds_with_metaspace_addr(char* metaspace_base, address cds_base) {
assert(cds_base != 0 && UseSharedSpaces, "Only use with CDS");
assert(UseCompressedKlassPointers, "Only use with CompressedKlassPtrs");
address lower_base = MIN2((address)metaspace_base, cds_base);
address higher_address = MAX2((address)(cds_base + FileMapInfo::shared_spaces_size()),
(address)(metaspace_base + class_metaspace_size()));
return ((uint64_t)(higher_address - lower_base) < (uint64_t)max_juint);
}
// Try to allocate the metaspace at the requested addr.
void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base) {
assert(using_class_space(), "called improperly");
assert(UseCompressedKlassPointers, "Only use with CompressedKlassPtrs");
assert(class_metaspace_size() < KlassEncodingMetaspaceMax,
"Metaspace size is too big");
ReservedSpace metaspace_rs = ReservedSpace(class_metaspace_size(),
os::vm_allocation_granularity(),
false, requested_addr, 0);
if (!metaspace_rs.is_reserved()) {
if (UseSharedSpaces) {
// Keep trying to allocate the metaspace, increasing the requested_addr
// by 1GB each time, until we reach an address that will no longer allow
// use of CDS with compressed klass pointers.
char *addr = requested_addr;
while (!metaspace_rs.is_reserved() && (addr + 1*G > addr) &&
can_use_cds_with_metaspace_addr(addr + 1*G, cds_base)) {
addr = addr + 1*G;
metaspace_rs = ReservedSpace(class_metaspace_size(),
os::vm_allocation_granularity(), false, addr, 0);
}
}
// If no successful allocation then try to allocate the space anywhere. If
// that fails then OOM doom. At this point we cannot try allocating the
// metaspace as if UseCompressedKlassPointers is off because too much
// initialization has happened that depends on UseCompressedKlassPointers.
// So, UseCompressedKlassPointers cannot be turned off at this point.
if (!metaspace_rs.is_reserved()) {
metaspace_rs = ReservedSpace(class_metaspace_size(),
os::vm_allocation_granularity(), false);
if (!metaspace_rs.is_reserved()) {
vm_exit_during_initialization(err_msg("Could not allocate metaspace: %d bytes",
class_metaspace_size()));
}
}
}
// If we got here then the metaspace got allocated.
MemTracker::record_virtual_memory_type((address)metaspace_rs.base(), mtClass);
// Verify that we can use shared spaces. Otherwise, turn off CDS.
if (UseSharedSpaces && !can_use_cds_with_metaspace_addr(metaspace_rs.base(), cds_base)) {
FileMapInfo::stop_sharing_and_unmap(
"Could not allocate metaspace at a compatible address");
}
set_narrow_klass_base_and_shift((address)metaspace_rs.base(),
UseSharedSpaces ? (address)cds_base : 0);
initialize_class_space(metaspace_rs);
if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) {
gclog_or_tty->print_cr("Narrow klass base: " PTR_FORMAT ", Narrow klass shift: " SIZE_FORMAT,
Universe::narrow_klass_base(), Universe::narrow_klass_shift());
gclog_or_tty->print_cr("Metaspace Size: " SIZE_FORMAT " Address: " PTR_FORMAT " Req Addr: " PTR_FORMAT,
class_metaspace_size(), metaspace_rs.base(), requested_addr);
}
}
// For UseCompressedKlassPointers the class space is reserved above the top of
// the Java heap. The argument passed in is at the base of the compressed space.
void Metaspace::initialize_class_space(ReservedSpace rs) {
// The reserved space size may be bigger because of alignment, esp with UseLargePages
assert(rs.size() >= ClassMetaspaceSize,
err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), ClassMetaspaceSize));
assert(using_class_space(), "Must be using class space");
_class_space_list = new VirtualSpaceList(rs);
}
#endif
void Metaspace::global_initialize() {
// Initialize the alignment for shared spaces.
int max_alignment = os::vm_page_size();
size_t cds_total = 0;
set_class_metaspace_size(align_size_up(ClassMetaspaceSize,
os::vm_allocation_granularity()));
MetaspaceShared::set_max_alignment(max_alignment);
if (DumpSharedSpaces) {
@ -2798,15 +2935,31 @@ void Metaspace::global_initialize() {
// Initialize with the sum of the shared space sizes. The read-only
// and read write metaspace chunks will be allocated out of this and the
// remainder is the misc code and data chunks.
size_t total = align_size_up(SharedReadOnlySize + SharedReadWriteSize +
SharedMiscDataSize + SharedMiscCodeSize,
os::vm_allocation_granularity());
size_t word_size = total/wordSize;
_space_list = new VirtualSpaceList(word_size);
cds_total = FileMapInfo::shared_spaces_size();
_space_list = new VirtualSpaceList(cds_total/wordSize);
#ifdef _LP64
// Set the compressed klass pointer base so that decoding of these pointers works
// properly when creating the shared archive.
assert(UseCompressedOops && UseCompressedKlassPointers,
"UseCompressedOops and UseCompressedKlassPointers must be set");
Universe::set_narrow_klass_base((address)_space_list->current_virtual_space()->bottom());
if (TraceMetavirtualspaceAllocation && Verbose) {
gclog_or_tty->print_cr("Setting_narrow_klass_base to Address: " PTR_FORMAT,
_space_list->current_virtual_space()->bottom());
}
// Set the shift to zero.
assert(class_metaspace_size() < (uint64_t)(max_juint) - cds_total,
"CDS region is too large");
Universe::set_narrow_klass_shift(0);
#endif
} else {
// If using shared space, open the file that contains the shared space
// and map in the memory before initializing the rest of metaspace (so
// the addresses don't conflict)
address cds_address = NULL;
if (UseSharedSpaces) {
FileMapInfo* mapinfo = new FileMapInfo();
memset(mapinfo, 0, sizeof(FileMapInfo));
@ -2821,8 +2974,22 @@ void Metaspace::global_initialize() {
assert(!mapinfo->is_open() && !UseSharedSpaces,
"archive file not closed or shared spaces not disabled.");
}
cds_total = FileMapInfo::shared_spaces_size();
cds_address = (address)mapinfo->region_base(0);
}
#ifdef _LP64
// If UseCompressedKlassPointers is set then allocate the metaspace area
// above the heap and above the CDS area (if it exists).
if (using_class_space()) {
if (UseSharedSpaces) {
allocate_metaspace_compressed_klass_ptrs((char *)(cds_address + cds_total), cds_address);
} else {
allocate_metaspace_compressed_klass_ptrs((char *)CompressedKlassPointersBase, 0);
}
}
#endif
// Initialize these before initializing the VirtualSpaceList
_first_chunk_word_size = InitialBootClassLoaderMetaspaceSize / BytesPerWord;
_first_chunk_word_size = align_word_size_up(_first_chunk_word_size);
@ -2840,39 +3007,28 @@ void Metaspace::global_initialize() {
}
}
// For UseCompressedKlassPointers the class space is reserved as a piece of the
// Java heap because the compression algorithm is the same for each. The
// argument passed in is at the top of the compressed space
void Metaspace::initialize_class_space(ReservedSpace rs) {
// The reserved space size may be bigger because of alignment, esp with UseLargePages
assert(rs.size() >= ClassMetaspaceSize,
err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), ClassMetaspaceSize));
_class_space_list = new VirtualSpaceList(rs);
}
void Metaspace::initialize(Mutex* lock,
MetaspaceType type) {
void Metaspace::initialize(Mutex* lock, MetaspaceType type) {
assert(space_list() != NULL,
"Metadata VirtualSpaceList has not been initialized");
_vsm = new SpaceManager(Metaspace::NonClassType, lock, space_list());
_vsm = new SpaceManager(NonClassType, lock, space_list());
if (_vsm == NULL) {
return;
}
size_t word_size;
size_t class_word_size;
vsm()->get_initial_chunk_sizes(type,
&word_size,
&class_word_size);
vsm()->get_initial_chunk_sizes(type, &word_size, &class_word_size);
assert(class_space_list() != NULL,
"Class VirtualSpaceList has not been initialized");
if (using_class_space()) {
assert(class_space_list() != NULL,
"Class VirtualSpaceList has not been initialized");
// Allocate SpaceManager for classes.
_class_vsm = new SpaceManager(Metaspace::ClassType, lock, class_space_list());
if (_class_vsm == NULL) {
return;
// Allocate SpaceManager for classes.
_class_vsm = new SpaceManager(ClassType, lock, class_space_list());
if (_class_vsm == NULL) {
return;
}
}
MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag);
@ -2888,11 +3044,13 @@ void Metaspace::initialize(Mutex* lock,
}
// Allocate chunk for class metadata objects
Metachunk* class_chunk =
class_space_list()->get_initialization_chunk(class_word_size,
class_vsm()->medium_chunk_bunch());
if (class_chunk != NULL) {
class_vsm()->add_chunk(class_chunk, true);
if (using_class_space()) {
Metachunk* class_chunk =
class_space_list()->get_initialization_chunk(class_word_size,
class_vsm()->medium_chunk_bunch());
if (class_chunk != NULL) {
class_vsm()->add_chunk(class_chunk, true);
}
}
_alloc_record_head = NULL;
@ -2906,7 +3064,8 @@ size_t Metaspace::align_word_size_up(size_t word_size) {
MetaWord* Metaspace::allocate(size_t word_size, MetadataType mdtype) {
// DumpSharedSpaces doesn't use class metadata area (yet)
if (mdtype == ClassType && !DumpSharedSpaces) {
// Also, don't use class_vsm() unless UseCompressedKlassPointers is true.
if (mdtype == ClassType && using_class_space()) {
return class_vsm()->allocate(word_size);
} else {
return vsm()->allocate(word_size);
@ -2937,14 +3096,19 @@ char* Metaspace::bottom() const {
}
size_t Metaspace::used_words_slow(MetadataType mdtype) const {
// return vsm()->allocated_used_words();
return mdtype == ClassType ? class_vsm()->sum_used_in_chunks_in_use() :
vsm()->sum_used_in_chunks_in_use(); // includes overhead!
if (mdtype == ClassType) {
return using_class_space() ? class_vsm()->sum_used_in_chunks_in_use() : 0;
} else {
return vsm()->sum_used_in_chunks_in_use(); // includes overhead!
}
}
size_t Metaspace::free_words(MetadataType mdtype) const {
return mdtype == ClassType ? class_vsm()->sum_free_in_chunks_in_use() :
vsm()->sum_free_in_chunks_in_use();
if (mdtype == ClassType) {
return using_class_space() ? class_vsm()->sum_free_in_chunks_in_use() : 0;
} else {
return vsm()->sum_free_in_chunks_in_use();
}
}
// Space capacity in the Metaspace. It includes
@ -2953,8 +3117,11 @@ size_t Metaspace::free_words(MetadataType mdtype) const {
// in the space available in the dictionary which
// is already counted in some chunk.
size_t Metaspace::capacity_words_slow(MetadataType mdtype) const {
return mdtype == ClassType ? class_vsm()->sum_capacity_in_chunks_in_use() :
vsm()->sum_capacity_in_chunks_in_use();
if (mdtype == ClassType) {
return using_class_space() ? class_vsm()->sum_capacity_in_chunks_in_use() : 0;
} else {
return vsm()->sum_capacity_in_chunks_in_use();
}
}
size_t Metaspace::used_bytes_slow(MetadataType mdtype) const {
@ -2977,8 +3144,8 @@ void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) {
#endif
return;
}
if (is_class) {
class_vsm()->deallocate(ptr, word_size);
if (is_class && using_class_space()) {
class_vsm()->deallocate(ptr, word_size);
} else {
vsm()->deallocate(ptr, word_size);
}
@ -2992,7 +3159,7 @@ void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) {
#endif
return;
}
if (is_class) {
if (is_class && using_class_space()) {
class_vsm()->deallocate(ptr, word_size);
} else {
vsm()->deallocate(ptr, word_size);
@ -3101,14 +3268,18 @@ void Metaspace::purge() {
MutexLockerEx cl(SpaceManager::expand_lock(),
Mutex::_no_safepoint_check_flag);
space_list()->purge();
class_space_list()->purge();
if (using_class_space()) {
class_space_list()->purge();
}
}
void Metaspace::print_on(outputStream* out) const {
// Print both class virtual space counts and metaspace.
if (Verbose) {
vsm()->print_on(out);
vsm()->print_on(out);
if (using_class_space()) {
class_vsm()->print_on(out);
}
}
}
@ -3122,17 +3293,21 @@ bool Metaspace::contains(const void * ptr) {
// be needed. Note, locking this can cause inversion problems with the
// caller in MetaspaceObj::is_metadata() function.
return space_list()->contains(ptr) ||
class_space_list()->contains(ptr);
(using_class_space() && class_space_list()->contains(ptr));
}
void Metaspace::verify() {
vsm()->verify();
class_vsm()->verify();
if (using_class_space()) {
class_vsm()->verify();
}
}
void Metaspace::dump(outputStream* const out) const {
out->print_cr("\nVirtual space manager: " INTPTR_FORMAT, vsm());
vsm()->dump(out);
out->print_cr("\nClass space manager: " INTPTR_FORMAT, class_vsm());
class_vsm()->dump(out);
if (using_class_space()) {
out->print_cr("\nClass space manager: " INTPTR_FORMAT, class_vsm());
class_vsm()->dump(out);
}
}

View File

@ -105,6 +105,16 @@ class Metaspace : public CHeapObj<mtClass> {
// Align up the word size to the allocation word size
static size_t align_word_size_up(size_t);
// Aligned size of the metaspace.
static size_t _class_metaspace_size;
static size_t class_metaspace_size() {
return _class_metaspace_size;
}
static void set_class_metaspace_size(size_t metaspace_size) {
_class_metaspace_size = metaspace_size;
}
static size_t _first_chunk_word_size;
static size_t _first_class_chunk_word_size;
@ -126,11 +136,26 @@ class Metaspace : public CHeapObj<mtClass> {
static VirtualSpaceList* space_list() { return _space_list; }
static VirtualSpaceList* class_space_list() { return _class_space_list; }
static VirtualSpaceList* get_space_list(MetadataType mdtype) {
assert(mdtype != MetadataTypeCount, "MetadaTypeCount can't be used as mdtype");
return mdtype == ClassType ? class_space_list() : space_list();
}
// This is used by DumpSharedSpaces only, where only _vsm is used. So we will
// maintain a single list for now.
void record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size);
#ifdef _LP64
static void set_narrow_klass_base_and_shift(address metaspace_base, address cds_base);
// Returns true if can use CDS with metaspace allocated as specified address.
static bool can_use_cds_with_metaspace_addr(char* metaspace_base, address cds_base);
static void allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base);
static void initialize_class_space(ReservedSpace rs);
#endif
class AllocRecord : public CHeapObj<mtClass> {
public:
AllocRecord(address ptr, MetaspaceObj::Type type, int byte_size)
@ -151,7 +176,6 @@ class Metaspace : public CHeapObj<mtClass> {
// Initialize globals for Metaspace
static void global_initialize();
static void initialize_class_space(ReservedSpace rs);
static size_t first_chunk_word_size() { return _first_chunk_word_size; }
static size_t first_class_chunk_word_size() { return _first_class_chunk_word_size; }
@ -172,8 +196,6 @@ class Metaspace : public CHeapObj<mtClass> {
MetaWord* expand_and_allocate(size_t size,
MetadataType mdtype);
static bool is_initialized() { return _class_space_list != NULL; }
static bool contains(const void *ptr);
void dump(outputStream* const out) const;
@ -190,11 +212,16 @@ class Metaspace : public CHeapObj<mtClass> {
};
void iterate(AllocRecordClosure *closure);
// Return TRUE only if UseCompressedKlassPointers is True and DumpSharedSpaces is False.
static bool using_class_space() {
return NOT_LP64(false) LP64_ONLY(UseCompressedKlassPointers && !DumpSharedSpaces);
}
};
class MetaspaceAux : AllStatic {
static size_t free_chunks_total(Metaspace::MetadataType mdtype);
static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype);
public:
// Statistics for class space and data space in metaspace.
@ -238,13 +265,15 @@ class MetaspaceAux : AllStatic {
// Used by MetaspaceCounters
static size_t free_chunks_total();
static size_t free_chunks_total_in_bytes();
static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype);
static size_t allocated_capacity_words(Metaspace::MetadataType mdtype) {
return _allocated_capacity_words[mdtype];
}
static size_t allocated_capacity_words() {
return _allocated_capacity_words[Metaspace::ClassType] +
_allocated_capacity_words[Metaspace::NonClassType];
return _allocated_capacity_words[Metaspace::NonClassType] +
(Metaspace::using_class_space() ?
_allocated_capacity_words[Metaspace::ClassType] : 0);
}
static size_t allocated_capacity_bytes(Metaspace::MetadataType mdtype) {
return allocated_capacity_words(mdtype) * BytesPerWord;
@ -257,8 +286,9 @@ class MetaspaceAux : AllStatic {
return _allocated_used_words[mdtype];
}
static size_t allocated_used_words() {
return _allocated_used_words[Metaspace::ClassType] +
_allocated_used_words[Metaspace::NonClassType];
return _allocated_used_words[Metaspace::NonClassType] +
(Metaspace::using_class_space() ?
_allocated_used_words[Metaspace::ClassType] : 0);
}
static size_t allocated_used_bytes(Metaspace::MetadataType mdtype) {
return allocated_used_words(mdtype) * BytesPerWord;
@ -268,6 +298,7 @@ class MetaspaceAux : AllStatic {
}
static size_t free_bytes();
static size_t free_bytes(Metaspace::MetadataType mdtype);
// Total capacity in all Metaspaces
static size_t capacity_bytes_slow() {
@ -300,6 +331,7 @@ class MetaspaceAux : AllStatic {
static void print_on(outputStream * out);
static void print_on(outputStream * out, Metaspace::MetadataType mdtype);
static void print_class_waste(outputStream* out);
static void print_waste(outputStream* out);
static void dump(outputStream* out);
static void verify_free_chunks();

View File

@ -25,11 +25,47 @@
#include "precompiled.hpp"
#include "memory/metaspaceCounters.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/globals.hpp"
#include "runtime/perfData.hpp"
#include "utilities/exceptions.hpp"
MetaspaceCounters* MetaspaceCounters::_metaspace_counters = NULL;
class MetaspacePerfCounters: public CHeapObj<mtInternal> {
friend class VMStructs;
PerfVariable* _capacity;
PerfVariable* _used;
PerfVariable* _max_capacity;
size_t MetaspaceCounters::calc_total_capacity() {
PerfVariable* create_variable(const char *ns, const char *name, size_t value, TRAPS) {
const char *path = PerfDataManager::counter_name(ns, name);
return PerfDataManager::create_variable(SUN_GC, path, PerfData::U_Bytes, value, THREAD);
}
void create_constant(const char *ns, const char *name, size_t value, TRAPS) {
const char *path = PerfDataManager::counter_name(ns, name);
PerfDataManager::create_constant(SUN_GC, path, PerfData::U_Bytes, value, THREAD);
}
public:
MetaspacePerfCounters(const char* ns, size_t min_capacity, size_t curr_capacity, size_t max_capacity, size_t used) {
EXCEPTION_MARK;
ResourceMark rm;
create_constant(ns, "minCapacity", min_capacity, THREAD);
_capacity = create_variable(ns, "capacity", curr_capacity, THREAD);
_max_capacity = create_variable(ns, "maxCapacity", max_capacity, THREAD);
_used = create_variable(ns, "used", used, THREAD);
}
void update(size_t capacity, size_t max_capacity, size_t used) {
_capacity->set_value(capacity);
_max_capacity->set_value(max_capacity);
_used->set_value(used);
}
};
MetaspacePerfCounters* MetaspaceCounters::_perf_counters = NULL;
size_t MetaspaceCounters::calculate_capacity() {
// The total capacity is the sum of
// 1) capacity of Metachunks in use by all Metaspaces
// 2) unused space at the end of each Metachunk
@ -39,95 +75,65 @@ size_t MetaspaceCounters::calc_total_capacity() {
return total_capacity;
}
MetaspaceCounters::MetaspaceCounters() :
_capacity(NULL),
_used(NULL),
_max_capacity(NULL) {
if (UsePerfData) {
size_t min_capacity = MetaspaceAux::min_chunk_size();
size_t max_capacity = MetaspaceAux::reserved_in_bytes();
size_t curr_capacity = calc_total_capacity();
size_t used = MetaspaceAux::allocated_used_bytes();
initialize(min_capacity, max_capacity, curr_capacity, used);
}
}
static PerfVariable* create_ms_variable(const char *ns,
const char *name,
size_t value,
TRAPS) {
const char *path = PerfDataManager::counter_name(ns, name);
PerfVariable *result =
PerfDataManager::create_variable(SUN_GC, path, PerfData::U_Bytes, value,
CHECK_NULL);
return result;
}
static void create_ms_constant(const char *ns,
const char *name,
size_t value,
TRAPS) {
const char *path = PerfDataManager::counter_name(ns, name);
PerfDataManager::create_constant(SUN_GC, path, PerfData::U_Bytes, value, CHECK);
}
void MetaspaceCounters::initialize(size_t min_capacity,
size_t max_capacity,
size_t curr_capacity,
size_t used) {
if (UsePerfData) {
EXCEPTION_MARK;
ResourceMark rm;
const char *ms = "metaspace";
create_ms_constant(ms, "minCapacity", min_capacity, CHECK);
_max_capacity = create_ms_variable(ms, "maxCapacity", max_capacity, CHECK);
_capacity = create_ms_variable(ms, "capacity", curr_capacity, CHECK);
_used = create_ms_variable(ms, "used", used, CHECK);
}
}
void MetaspaceCounters::update_capacity() {
assert(UsePerfData, "Should not be called unless being used");
size_t total_capacity = calc_total_capacity();
_capacity->set_value(total_capacity);
}
void MetaspaceCounters::update_used() {
assert(UsePerfData, "Should not be called unless being used");
size_t used_in_bytes = MetaspaceAux::allocated_used_bytes();
_used->set_value(used_in_bytes);
}
void MetaspaceCounters::update_max_capacity() {
assert(UsePerfData, "Should not be called unless being used");
assert(_max_capacity != NULL, "Should be initialized");
size_t reserved_in_bytes = MetaspaceAux::reserved_in_bytes();
_max_capacity->set_value(reserved_in_bytes);
}
void MetaspaceCounters::update_all() {
if (UsePerfData) {
update_used();
update_capacity();
update_max_capacity();
}
}
void MetaspaceCounters::initialize_performance_counters() {
if (UsePerfData) {
assert(_metaspace_counters == NULL, "Should only be initialized once");
_metaspace_counters = new MetaspaceCounters();
assert(_perf_counters == NULL, "Should only be initialized once");
size_t min_capacity = MetaspaceAux::min_chunk_size();
size_t capacity = calculate_capacity();
size_t max_capacity = MetaspaceAux::reserved_in_bytes();
size_t used = MetaspaceAux::allocated_used_bytes();
_perf_counters = new MetaspacePerfCounters("metaspace", min_capacity, capacity, max_capacity, used);
}
}
void MetaspaceCounters::update_performance_counters() {
if (UsePerfData) {
assert(_metaspace_counters != NULL, "Should be initialized");
_metaspace_counters->update_all();
assert(_perf_counters != NULL, "Should be initialized");
size_t capacity = calculate_capacity();
size_t max_capacity = MetaspaceAux::reserved_in_bytes();
size_t used = MetaspaceAux::allocated_used_bytes();
_perf_counters->update(capacity, max_capacity, used);
}
}
MetaspacePerfCounters* CompressedClassSpaceCounters::_perf_counters = NULL;
size_t CompressedClassSpaceCounters::calculate_capacity() {
return MetaspaceAux::allocated_capacity_bytes(_class_type) +
MetaspaceAux::free_bytes(_class_type) +
MetaspaceAux::free_chunks_total_in_bytes(_class_type);
}
void CompressedClassSpaceCounters::update_performance_counters() {
if (UsePerfData && UseCompressedKlassPointers) {
assert(_perf_counters != NULL, "Should be initialized");
size_t capacity = calculate_capacity();
size_t max_capacity = MetaspaceAux::reserved_in_bytes(_class_type);
size_t used = MetaspaceAux::allocated_used_bytes(_class_type);
_perf_counters->update(capacity, max_capacity, used);
}
}
void CompressedClassSpaceCounters::initialize_performance_counters() {
if (UsePerfData) {
assert(_perf_counters == NULL, "Should only be initialized once");
const char* ns = "compressedclassspace";
if (UseCompressedKlassPointers) {
size_t min_capacity = MetaspaceAux::min_chunk_size();
size_t capacity = calculate_capacity();
size_t max_capacity = MetaspaceAux::reserved_in_bytes(_class_type);
size_t used = MetaspaceAux::allocated_used_bytes(_class_type);
_perf_counters = new MetaspacePerfCounters(ns, min_capacity, capacity, max_capacity, used);
} else {
_perf_counters = new MetaspacePerfCounters(ns, 0, 0, 0, 0);
}
}
}

View File

@ -25,31 +25,27 @@
#ifndef SHARE_VM_MEMORY_METASPACECOUNTERS_HPP
#define SHARE_VM_MEMORY_METASPACECOUNTERS_HPP
#include "runtime/perfData.hpp"
#include "memory/metaspace.hpp"
class MetaspacePerfCounters;
class MetaspaceCounters: public AllStatic {
static MetaspacePerfCounters* _perf_counters;
static size_t calculate_capacity();
class MetaspaceCounters: public CHeapObj<mtClass> {
friend class VMStructs;
PerfVariable* _capacity;
PerfVariable* _used;
PerfVariable* _max_capacity;
static MetaspaceCounters* _metaspace_counters;
void initialize(size_t min_capacity,
size_t max_capacity,
size_t curr_capacity,
size_t used);
size_t calc_total_capacity();
public:
MetaspaceCounters();
~MetaspaceCounters();
void update_capacity();
void update_used();
void update_max_capacity();
void update_all();
static void initialize_performance_counters();
static void update_performance_counters();
};
class CompressedClassSpaceCounters: public AllStatic {
static MetaspacePerfCounters* _perf_counters;
static size_t calculate_capacity();
static const Metaspace::MetadataType _class_type = Metaspace::ClassType;
public:
static void initialize_performance_counters();
static void update_performance_counters();
};
#endif // SHARE_VM_MEMORY_METASPACECOUNTERS_HPP

View File

@ -52,7 +52,6 @@ void MetaspaceShared::serialize(SerializeClosure* soc) {
int tag = 0;
soc->do_tag(--tag);
assert(!UseCompressedOops, "UseCompressedOops doesn't work with shared archive");
// Verify the sizes of various metadata in the system.
soc->do_tag(sizeof(Method));
soc->do_tag(sizeof(ConstMethod));

View File

@ -145,8 +145,6 @@ NarrowPtrStruct Universe::_narrow_oop = { NULL, 0, true };
NarrowPtrStruct Universe::_narrow_klass = { NULL, 0, true };
address Universe::_narrow_ptrs_base;
size_t Universe::_class_metaspace_size;
void Universe::basic_type_classes_do(void f(Klass*)) {
f(boolArrayKlassObj());
f(byteArrayKlassObj());
@ -641,6 +639,8 @@ jint universe_init() {
return status;
}
Metaspace::global_initialize();
// Create memory for metadata. Must be after initializing heap for
// DumpSharedSpaces.
ClassLoaderData::init_null_class_loader_data();
@ -681,25 +681,27 @@ static const uint64_t NarrowOopHeapMax = (uint64_t(max_juint) + 1);
// 32Gb
// OopEncodingHeapMax == NarrowOopHeapMax << LogMinObjAlignmentInBytes;
char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) {
char* Universe::preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode) {
assert(is_size_aligned((size_t)OopEncodingHeapMax, alignment), "Must be");
assert(is_size_aligned((size_t)NarrowOopHeapMax, alignment), "Must be");
assert(is_size_aligned(heap_size, alignment), "Must be");
uintx heap_base_min_address_aligned = align_size_up(HeapBaseMinAddress, alignment);
size_t base = 0;
#ifdef _LP64
if (UseCompressedOops) {
assert(mode == UnscaledNarrowOop ||
mode == ZeroBasedNarrowOop ||
mode == HeapBasedNarrowOop, "mode is invalid");
const size_t total_size = heap_size + HeapBaseMinAddress;
const size_t total_size = heap_size + heap_base_min_address_aligned;
// Return specified base for the first request.
if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) {
base = HeapBaseMinAddress;
base = heap_base_min_address_aligned;
// If the total size and the metaspace size are small enough to allow
// UnscaledNarrowOop then just use UnscaledNarrowOop.
} else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop) &&
(!UseCompressedKlassPointers ||
(((OopEncodingHeapMax - heap_size) + Universe::class_metaspace_size()) <= KlassEncodingMetaspaceMax))) {
// We don't need to check the metaspace size here because it is always smaller
// than total_size.
// If the total size is small enough to allow UnscaledNarrowOop then
// just use UnscaledNarrowOop.
} else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop)) {
if ((total_size <= NarrowOopHeapMax) && (mode == UnscaledNarrowOop) &&
(Universe::narrow_oop_shift() == 0)) {
// Use 32-bits oops without encoding and
@ -716,13 +718,6 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) {
base = (OopEncodingHeapMax - heap_size);
}
}
// See if ZeroBaseNarrowOop encoding will work for a heap based at
// (KlassEncodingMetaspaceMax - class_metaspace_size()).
} else if (UseCompressedKlassPointers && (mode != HeapBasedNarrowOop) &&
(Universe::class_metaspace_size() + HeapBaseMinAddress <= KlassEncodingMetaspaceMax) &&
(KlassEncodingMetaspaceMax + heap_size - Universe::class_metaspace_size() <= OopEncodingHeapMax)) {
base = (KlassEncodingMetaspaceMax - Universe::class_metaspace_size());
} else {
// UnscaledNarrowOop encoding didn't work, and no base was found for ZeroBasedOops or
// HeapBasedNarrowOop encoding was requested. So, can't reserve below 32Gb.
@ -732,8 +727,7 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) {
// Set narrow_oop_base and narrow_oop_use_implicit_null_checks
// used in ReservedHeapSpace() constructors.
// The final values will be set in initialize_heap() below.
if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax) &&
(!UseCompressedKlassPointers || (base + Universe::class_metaspace_size()) <= KlassEncodingMetaspaceMax)) {
if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax)) {
// Use zero based compressed oops
Universe::set_narrow_oop_base(NULL);
// Don't need guard page for implicit checks in indexed
@ -754,6 +748,8 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) {
}
}
#endif
assert(is_ptr_aligned((char*)base, alignment), "Must be");
return (char*)base; // also return NULL (don't care) for 32-bit VM
}
@ -816,9 +812,7 @@ jint Universe::initialize_heap() {
tty->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB",
Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M);
}
if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax) ||
(UseCompressedKlassPointers &&
((uint64_t)Universe::heap()->base() + Universe::class_metaspace_size() > KlassEncodingMetaspaceMax))) {
if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax)) {
// Can't reserve heap below 32Gb.
// keep the Universe::narrow_oop_base() set in Universe::reserve_heap()
Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes);
@ -849,20 +843,16 @@ jint Universe::initialize_heap() {
}
}
}
if (verbose) {
tty->cr();
tty->cr();
}
if (UseCompressedKlassPointers) {
Universe::set_narrow_klass_base(Universe::narrow_oop_base());
Universe::set_narrow_klass_shift(MIN2(Universe::narrow_oop_shift(), LogKlassAlignmentInBytes));
}
Universe::set_narrow_ptrs_base(Universe::narrow_oop_base());
}
// Universe::narrow_oop_base() is one page below the metaspace
// base. The actual metaspace base depends on alignment constraints
// so we don't know its exact location here.
assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() - os::vm_page_size() - ClassMetaspaceSize) ||
// Universe::narrow_oop_base() is one page below the heap.
assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() -
os::vm_page_size()) ||
Universe::narrow_oop_base() == NULL, "invalid value");
assert(Universe::narrow_oop_shift() == LogMinObjAlignmentInBytes ||
Universe::narrow_oop_shift() == 0, "invalid value");
@ -882,35 +872,36 @@ jint Universe::initialize_heap() {
// Reserve the Java heap, which is now the same for all GCs.
ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) {
// Add in the class metaspace area so the classes in the headers can
// be compressed the same as instances.
// Need to round class space size up because it's below the heap and
// the actual alignment depends on its size.
Universe::set_class_metaspace_size(align_size_up(ClassMetaspaceSize, alignment));
size_t total_reserved = align_size_up(heap_size + Universe::class_metaspace_size(), alignment);
size_t total_reserved = align_size_up(heap_size, alignment);
assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())),
"heap size is too big for compressed oops");
char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop);
ReservedHeapSpace total_rs(total_reserved, alignment, UseLargePages, addr);
bool use_large_pages = UseLargePages && is_size_aligned(alignment, os::large_page_size());
assert(!UseLargePages
|| UseParallelOldGC
|| use_large_pages, "Wrong alignment to use large pages");
char* addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::UnscaledNarrowOop);
ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, addr);
if (UseCompressedOops) {
if (addr != NULL && !total_rs.is_reserved()) {
// Failed to reserve at specified address - the requested memory
// region is taken already, for example, by 'java' launcher.
// Try again to reserver heap higher.
addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop);
addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::ZeroBasedNarrowOop);
ReservedHeapSpace total_rs0(total_reserved, alignment,
UseLargePages, addr);
use_large_pages, addr);
if (addr != NULL && !total_rs0.is_reserved()) {
// Failed to reserve at specified address again - give up.
addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop);
addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::HeapBasedNarrowOop);
assert(addr == NULL, "");
ReservedHeapSpace total_rs1(total_reserved, alignment,
UseLargePages, addr);
use_large_pages, addr);
total_rs = total_rs1;
} else {
total_rs = total_rs0;
@ -923,28 +914,17 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) {
return total_rs;
}
// Split the reserved space into main Java heap and a space for
// classes so that they can be compressed using the same algorithm
// as compressed oops. If compress oops and compress klass ptrs are
// used we need the meta space first: if the alignment used for
// compressed oops is greater than the one used for compressed klass
// ptrs, a metadata space on top of the heap could become
// unreachable.
ReservedSpace class_rs = total_rs.first_part(Universe::class_metaspace_size());
ReservedSpace heap_rs = total_rs.last_part(Universe::class_metaspace_size(), alignment);
Metaspace::initialize_class_space(class_rs);
if (UseCompressedOops) {
// Universe::initialize_heap() will reset this to NULL if unscaled
// or zero-based narrow oops are actually used.
address base = (address)(total_rs.base() - os::vm_page_size());
Universe::set_narrow_oop_base(base);
}
return heap_rs;
return total_rs;
}
// It's the caller's repsonsibility to ensure glitch-freedom
// It's the caller's responsibility to ensure glitch-freedom
// (if required).
void Universe::update_heap_info_at_gc() {
_heap_capacity_at_last_gc = heap()->capacity();
@ -1135,6 +1115,8 @@ bool universe_post_init() {
// Initialize performance counters for metaspaces
MetaspaceCounters::initialize_performance_counters();
CompressedClassSpaceCounters::initialize_performance_counters();
MemoryService::add_metaspace_memory_pools();
GC_locker::unlock(); // allow gc after bootstrapping

Some files were not shown because too many files have changed in this diff Show More