mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-31 13:38:47 +00:00
Merge
This commit is contained in:
commit
4af2b012c3
1
.hgtags
1
.hgtags
@ -583,3 +583,4 @@ c0023e364b6f130cb1e93747b796d8718d544db1 jdk-14+8
|
||||
18f189e69b29f8215a3500b875127ed4fb2d977a jdk-14+9
|
||||
ececb6dae777e622abda42c705fd984a42f46b5a jdk-14+10
|
||||
bf4c808a4488025a415f867e54c8b088417e08a0 jdk-14+11
|
||||
8570f22b9b6ac6bec673899b582150865696e425 jdk-14+12
|
||||
|
||||
@ -572,6 +572,7 @@ CC: Sun C++ 5.13 SunOS_i386 151846-10 2015/10/30</code></pre>
|
||||
<li><code>CONF_CHECK</code></li>
|
||||
<li><code>COMPARE_BUILD</code></li>
|
||||
<li><code>JDK_FILTER</code></li>
|
||||
<li><code>SPEC_FILTER</code></li>
|
||||
</ul>
|
||||
<h2 id="running-tests">Running Tests</h2>
|
||||
<p>Most of the JDK tests are using the <a href="http://openjdk.java.net/jtreg">JTReg</a> test framework. Make sure that your configuration knows where to find your installation of JTReg. If this is not picked up automatically, use the <code>--with-jtreg=<path to jtreg home></code> option to point to the JTReg framework. Note that this option should point to the JTReg home, i.e. the top directory, containing <code>lib/jtreg.jar</code> etc.</p>
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
$ make test-jdk_lang JTREG="JOBS=8"
|
||||
$ make test TEST=jdk_lang
|
||||
$ make test-only TEST="gtest:LogTagSet gtest:LogTagSetDescriptions" GTEST="REPEAT=-1"
|
||||
$ make test TEST="hotspot:hotspot_gc" JTREG="JOBS=1;TIMEOUT=8;VM_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"
|
||||
$ make test TEST="hotspot:hotspot_gc" JTREG="JOBS=1;TIMEOUT_FACTOR=8;VM_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"
|
||||
$ make test TEST="jtreg:test/hotspot:hotspot_gc test/hotspot/jtreg/native_sanity/JniVersion.java"
|
||||
$ make test TEST="micro:java.lang.reflect" MICRO="FORK=1;WARMUP_ITER=2"
|
||||
$ make exploded-test TEST=tier2</code></pre>
|
||||
@ -103,9 +103,9 @@ TEST FAILURE</code></pre>
|
||||
<p>Additional work data is stored in <code>build/$BUILD/test-support/$TEST_ID</code>. For some frameworks, this directory might contain information that is useful in determining the cause of a failed test.</p>
|
||||
<h2 id="test-suite-control">Test suite control</h2>
|
||||
<p>It is possible to control various aspects of the test suites using make control variables.</p>
|
||||
<p>These variables use a keyword=value approach to allow multiple values to be set. So, for instance, <code>JTREG="JOBS=1;TIMEOUT=8"</code> will set the JTReg concurrency level to 1 and the timeout factor to 8. This is equivalent to setting <code>JTREG_JOBS=1 JTREG_TIMEOUT=8</code>, but using the keyword format means that the <code>JTREG</code> variable is parsed and verified for correctness, so <code>JTREG="TMIEOUT=8"</code> would give an error, while <code>JTREG_TMIEOUT=8</code> would just pass unnoticed.</p>
|
||||
<p>These variables use a keyword=value approach to allow multiple values to be set. So, for instance, <code>JTREG="JOBS=1;TIMEOUT_FACTOR=8"</code> will set the JTReg concurrency level to 1 and the timeout factor to 8. This is equivalent to setting <code>JTREG_JOBS=1 JTREG_TIMEOUT_FACTOR=8</code>, but using the keyword format means that the <code>JTREG</code> variable is parsed and verified for correctness, so <code>JTREG="TMIEOUT_FACTOR=8"</code> would give an error, while <code>JTREG_TMIEOUT_FACTOR=8</code> would just pass unnoticed.</p>
|
||||
<p>To separate multiple keyword=value pairs, use <code>;</code> (semicolon). Since the shell normally eats <code>;</code>, the recommended usage is to write the assignment inside qoutes, e.g. <code>JTREG="...;..."</code>. This will also make sure spaces are preserved, as in <code>JTREG="VM_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"</code>.</p>
|
||||
<p>(Other ways are possible, e.g. using backslash: <code>JTREG=JOBS=1\;TIMEOUT=8</code>. Also, as a special technique, the string <code>%20</code> will be replaced with space for certain options, e.g. <code>JTREG=VM_OPTIONS=-XshowSettings%20-Xlog:gc+ref=debug</code>. This can be useful if you have layers of scripts and have trouble getting proper quoting of command line arguments through.)</p>
|
||||
<p>(Other ways are possible, e.g. using backslash: <code>JTREG=JOBS=1\;TIMEOUT_FACTOR=8</code>. Also, as a special technique, the string <code>%20</code> will be replaced with space for certain options, e.g. <code>JTREG=VM_OPTIONS=-XshowSettings%20-Xlog:gc+ref=debug</code>. This can be useful if you have layers of scripts and have trouble getting proper quoting of command line arguments through.)</p>
|
||||
<p>As far as possible, the names of the keywords have been standardized between test suites.</p>
|
||||
<h3 id="general-keywords-test_opts">General keywords (TEST_OPTS)</h3>
|
||||
<p>Some keywords are valid across different test suites. If you want to run tests from multiple test suites, or just don't want to care which test suite specific control variable to use, then you can use the general TEST_OPTS control variable.</p>
|
||||
|
||||
@ -23,7 +23,7 @@ Some example command-lines:
|
||||
$ make test-jdk_lang JTREG="JOBS=8"
|
||||
$ make test TEST=jdk_lang
|
||||
$ make test-only TEST="gtest:LogTagSet gtest:LogTagSetDescriptions" GTEST="REPEAT=-1"
|
||||
$ make test TEST="hotspot:hotspot_gc" JTREG="JOBS=1;TIMEOUT=8;VM_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"
|
||||
$ make test TEST="hotspot:hotspot_gc" JTREG="JOBS=1;TIMEOUT_FACTOR=8;VM_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"
|
||||
$ make test TEST="jtreg:test/hotspot:hotspot_gc test/hotspot/jtreg/native_sanity/JniVersion.java"
|
||||
$ make test TEST="micro:java.lang.reflect" MICRO="FORK=1;WARMUP_ITER=2"
|
||||
$ make exploded-test TEST=tier2
|
||||
@ -180,11 +180,11 @@ It is possible to control various aspects of the test suites using make control
|
||||
variables.
|
||||
|
||||
These variables use a keyword=value approach to allow multiple values to be
|
||||
set. So, for instance, `JTREG="JOBS=1;TIMEOUT=8"` will set the JTReg
|
||||
set. So, for instance, `JTREG="JOBS=1;TIMEOUT_FACTOR=8"` will set the JTReg
|
||||
concurrency level to 1 and the timeout factor to 8. This is equivalent to
|
||||
setting `JTREG_JOBS=1 JTREG_TIMEOUT=8`, but using the keyword format means that
|
||||
setting `JTREG_JOBS=1 JTREG_TIMEOUT_FACTOR=8`, but using the keyword format means that
|
||||
the `JTREG` variable is parsed and verified for correctness, so
|
||||
`JTREG="TMIEOUT=8"` would give an error, while `JTREG_TMIEOUT=8` would just
|
||||
`JTREG="TMIEOUT_FACTOR=8"` would give an error, while `JTREG_TMIEOUT_FACTOR=8` would just
|
||||
pass unnoticed.
|
||||
|
||||
To separate multiple keyword=value pairs, use `;` (semicolon). Since the shell
|
||||
@ -192,7 +192,7 @@ normally eats `;`, the recommended usage is to write the assignment inside
|
||||
qoutes, e.g. `JTREG="...;..."`. This will also make sure spaces are preserved,
|
||||
as in `JTREG="VM_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"`.
|
||||
|
||||
(Other ways are possible, e.g. using backslash: `JTREG=JOBS=1\;TIMEOUT=8`.
|
||||
(Other ways are possible, e.g. using backslash: `JTREG=JOBS=1\;TIMEOUT_FACTOR=8`.
|
||||
Also, as a special technique, the string `%20` will be replaced with space for
|
||||
certain options, e.g. `JTREG=VM_OPTIONS=-XshowSettings%20-Xlog:gc+ref=debug`.
|
||||
This can be useful if you have layers of scripts and have trouble getting
|
||||
|
||||
@ -87,6 +87,7 @@ public class HelloClasslist {
|
||||
String CICI = "string" + args.length + "string" + args.length;
|
||||
String CJ = "string" + System.currentTimeMillis();
|
||||
String JC = System.currentTimeMillis() + "string";
|
||||
String CD = "string" + (args.length/2.0);
|
||||
String CJC = "string" + System.currentTimeMillis() + "string";
|
||||
String CJCJ = "string" + System.currentTimeMillis() + "string" + System.currentTimeMillis();
|
||||
String CJCJC = "string" + System.currentTimeMillis() + "string" + System.currentTimeMillis() + "string";
|
||||
|
||||
@ -40,20 +40,21 @@ abstract class AbstractTypeListNode extends AbstractNamedNode {
|
||||
|
||||
void document(PrintWriter writer) {
|
||||
writer.println("<dt>" + name() + " Data");
|
||||
writer.println("<dd>");
|
||||
if (components.isEmpty()) {
|
||||
writer.println("<dd>(None)");
|
||||
writer.println("(None)");
|
||||
} else {
|
||||
writer.println("<dd><table><tr>");
|
||||
for (int i = maxStructIndent; i > 0; --i) {
|
||||
writer.print("<th style=\"width: 4%\">");
|
||||
}
|
||||
writer.println("<th style=\"width: 15%\"><th style=\"width: 65%\">");
|
||||
writer.println("");
|
||||
writer.println("<table><tr>");
|
||||
writer.println("<th class=\"bold\" style=\"width: 20%\" scope=\"col\">Type");
|
||||
writer.println("<th class=\"bold\" style=\"width: 15%\" scope=\"col\">Name");
|
||||
writer.println("<th class=\"bold\" style=\"width: 65%\" scope=\"col\">Description");
|
||||
writer.println("</tr>");
|
||||
for (Node node : components) {
|
||||
node.document(writer);
|
||||
}
|
||||
writer.println("</table>");
|
||||
}
|
||||
writer.println("</dd>");
|
||||
}
|
||||
|
||||
void genJavaClassBodyComponents(PrintWriter writer, int depth) {
|
||||
|
||||
@ -40,11 +40,11 @@ abstract class AbstractTypeNode extends AbstractNamedNode
|
||||
abstract String javaRead();
|
||||
|
||||
void document(PrintWriter writer) {
|
||||
docRowStart(writer);
|
||||
writer.println("<td colspan=" +
|
||||
(maxStructIndent - structIndent) + ">");
|
||||
writer.println(docType() + "<td><i>" + name() +
|
||||
"</i><td>" + comment() + " ");
|
||||
writer.println("<tr>");
|
||||
writer.println("<td>" + indentElement(structIndent, docType()));
|
||||
writer.println("<th scope=\"row\"><i>" + name() + "</i>");
|
||||
writer.println("<td>" + comment() + " ");
|
||||
writer.println("</tr>");
|
||||
}
|
||||
|
||||
String javaType() {
|
||||
|
||||
@ -46,13 +46,15 @@ class AltNode extends AbstractGroupNode implements TypeNode {
|
||||
}
|
||||
|
||||
void document(PrintWriter writer) {
|
||||
docRowStart(writer);
|
||||
writer.println("<td colspan=" +
|
||||
(maxStructIndent - structIndent + 1) + ">");
|
||||
writer.println("Case " + nameNode.name + " - if <i>" +
|
||||
((SelectNode)parent).typeNode.name +
|
||||
"</i> is " + nameNode.value() + ":");
|
||||
writer.println("<tr>");
|
||||
writer.println("<th colspan=\"2\" scope=\"row\">"
|
||||
+ indentElement(structIndent,
|
||||
"Case " + nameNode.name
|
||||
+ " - if <i>" + ((SelectNode)parent).typeNode.name + "</i>" +
|
||||
" is " + nameNode.value() + ":"));
|
||||
writer.println("<td>" + comment() + " ");
|
||||
writer.println("</tr>");
|
||||
|
||||
++structIndent;
|
||||
super.document(writer);
|
||||
--structIndent;
|
||||
|
||||
@ -54,10 +54,12 @@ class ConstantNode extends AbstractCommandNode {
|
||||
}
|
||||
|
||||
void document(PrintWriter writer) {
|
||||
|
||||
//Add anchor to each constant with format <constant table name>_<constant name>
|
||||
writer.println("<tr><td>" + name + "<td>" + nameNode.value() +
|
||||
"<td>" + comment() + " ");
|
||||
writer.println("<tr>"
|
||||
+ "<th scope=\"row\">" + name
|
||||
+ "<td class=\"centered\">" + nameNode.value()
|
||||
+ "<td>" + comment() + " "
|
||||
+ "</tr>");
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
|
||||
@ -54,14 +54,15 @@ class ConstantSetNode extends AbstractNamedNode {
|
||||
}
|
||||
|
||||
void document(PrintWriter writer) {
|
||||
writer.println("<h2 id=\"" + context.whereC + "\">" + name +
|
||||
" Constants</h2>");
|
||||
writer.println("<h2 id=\"" + context.whereC + "\">" + name + " Constants</h2>");
|
||||
writer.println(comment());
|
||||
writer.println("<table><tr>");
|
||||
writer.println("<th style=\"width: 20%\"><th style=\"width: 5%\"><th style=\"width: 65%\">");
|
||||
ConstantNode n;
|
||||
writer.println("<th class=\"bold\" style=\"width: 30%\" scope=\"col\">Name");
|
||||
writer.println("<th class=\"centered bold\" style=\"width: 5%\" scope=\"col\">Value");
|
||||
writer.println("<th class=\"bold\" style=\"width: 65%\" scope=\"col\">Description");
|
||||
writer.println("</tr>");
|
||||
for (Node node : components) {
|
||||
n = (ConstantNode)node;
|
||||
ConstantNode n = (ConstantNode)node;
|
||||
writer.println("<span id=\"" + name + "_" + n.name + "\"></span>");
|
||||
n.document(writer);
|
||||
}
|
||||
|
||||
@ -55,9 +55,10 @@ class ErrorNode extends AbstractCommandNode {
|
||||
if (com == null || com.length() == 0) {
|
||||
com = ConstantSetNode.getConstant("Error_" + name);
|
||||
}
|
||||
writer.println("<tr><td>" + "<a href=\"#" + NAME_OF_ERROR_TABLE + "_" + name + "\">"
|
||||
+ name + "</a></td>" +
|
||||
"<td>" + com + " </td></tr>");
|
||||
writer.println("<tr>"
|
||||
+ "<th scope=\"row\">" + "<a href=\"#" + NAME_OF_ERROR_TABLE + "_" + name + "\">" + name + "</a>"
|
||||
+ "<td>" + com + " "
|
||||
+ "</tr>");
|
||||
}
|
||||
|
||||
void genJavaComment(PrintWriter writer, int depth) {}
|
||||
|
||||
@ -38,17 +38,21 @@ class ErrorSetNode extends AbstractSimpleNode {
|
||||
}
|
||||
|
||||
void document(PrintWriter writer) {
|
||||
|
||||
writer.println("<dt>" + "Error Data");
|
||||
writer.println("<dt>Error Data</dt>");
|
||||
writer.print("<dd>");
|
||||
if (components.isEmpty()) {
|
||||
writer.println("<dd>(None)");
|
||||
writer.println("(None)");
|
||||
} else {
|
||||
writer.println("<dd><table>");
|
||||
for (Node node : components) {
|
||||
node.document(writer);
|
||||
}
|
||||
writer.println("</table>");
|
||||
writer.println("<table><tr>");
|
||||
writer.println("<th class=\"bold\" style=\"width: 20%\" scope=\"col\">Value");
|
||||
writer.println("<th class=\"bold\" scope=\"col\">Description");
|
||||
writer.println("</tr>");
|
||||
for (Node node : components) {
|
||||
node.document(writer);
|
||||
}
|
||||
writer.println("</table>");
|
||||
}
|
||||
writer.print("</dd>");
|
||||
}
|
||||
|
||||
void genJavaComment(PrintWriter writer, int depth) {}
|
||||
|
||||
@ -88,11 +88,10 @@ abstract class Node {
|
||||
void documentIndex(PrintWriter writer) {
|
||||
}
|
||||
|
||||
void docRowStart(PrintWriter writer) {
|
||||
writer.println("<tr>");
|
||||
if (structIndent > 0) {
|
||||
writer.println("<td colspan=" + structIndent + ">");
|
||||
}
|
||||
String indentElement(int depth, String content) {
|
||||
return depth > 0
|
||||
? "<div class=\"indent" + depth + "\">" + content + "</div>"
|
||||
: content;
|
||||
}
|
||||
|
||||
String comment() {
|
||||
|
||||
@ -44,15 +44,17 @@ class RepeatNode extends AbstractTypeNode {
|
||||
}
|
||||
|
||||
void document(PrintWriter writer) {
|
||||
docRowStart(writer);
|
||||
writer.println("<td colspan=" +
|
||||
(maxStructIndent - structIndent) + ">");
|
||||
writer.println("int<td><i>" + name + "</i><td>" +
|
||||
comment() + " ");
|
||||
docRowStart(writer);
|
||||
writer.println("<td colspan=" +
|
||||
(maxStructIndent - structIndent + 2) + ">");
|
||||
writer.println("Repeated <i>" + name + "</i> times:");
|
||||
writer.println("<tr>");
|
||||
writer.println("<td>" + indentElement(structIndent, "int"));
|
||||
writer.println("<th scope=\"row\"><i>" + name() + "</i>");
|
||||
writer.println("<td>" + comment() + " ");
|
||||
writer.println("</tr>");
|
||||
|
||||
writer.println("<tr>");
|
||||
writer.println("<th colspan=\"3\" scope=\"rowgroup\">"
|
||||
+ indentElement(structIndent, "Repeated <i>" + name() + "</i> times:"));
|
||||
writer.println("</tr>");
|
||||
|
||||
++structIndent;
|
||||
member.document(writer);
|
||||
--structIndent;
|
||||
|
||||
@ -46,15 +46,21 @@ class RootNode extends AbstractNamedNode {
|
||||
writer.println("<meta charset=\"utf-8\"/>");
|
||||
writer.println("<title>" + comment() + "</title>");
|
||||
writer.println("<style>");
|
||||
writer.println("body {background-color:white;}");
|
||||
writer.println("table {border: 1px solid grey; border-spacing:0px; border-collapse: separate; width: 90%;}");
|
||||
writer.println("td, th {padding: 3px; border: 1px solid black;}");
|
||||
writer.println("body { background-color:white; }");
|
||||
writer.println("table { border: 1px solid grey; border-spacing:0px; border-collapse: separate; width: 90%; }");
|
||||
writer.println("td, th { padding: 3px; border: 1px solid black; font-weight: normal; text-align: left; }");
|
||||
writer.println(".bold { font-weight: bold; }");
|
||||
writer.println(".centered { text-align: center; }");
|
||||
for (int i = 0; i < maxStructIndent; i++) {
|
||||
// each level is 40px
|
||||
writer.println(".indent" + i + " { padding-left: " + (i * 40) + "px; }");
|
||||
}
|
||||
writer.println("</style>");
|
||||
writer.println("</head>");
|
||||
writer.println("<body>");
|
||||
writer.println("<div class=\"centered\" role=\"banner\">");
|
||||
writer.println("<header>");
|
||||
writer.println("<h1 id=\"Protocol_Details\">Java Debug Wire Protocol Details</h1>");
|
||||
writer.println("</div>");
|
||||
writer.println("</header>");
|
||||
writer.println("<nav>");
|
||||
writer.println("<ul>");
|
||||
for (Node node : components) {
|
||||
@ -62,11 +68,11 @@ class RootNode extends AbstractNamedNode {
|
||||
}
|
||||
writer.println("</ul>");
|
||||
writer.println("</nav>");
|
||||
writer.println("<div role=\"main\">");
|
||||
writer.println("<main>");
|
||||
for (Node node : components) {
|
||||
node.document(writer);
|
||||
}
|
||||
writer.println("</div>");
|
||||
writer.println("</main>");
|
||||
writer.println("</body></html>");
|
||||
}
|
||||
|
||||
|
||||
@ -3569,7 +3569,7 @@ encode %{
|
||||
// Store a non-null value into the box to avoid looking like a re-entrant
|
||||
// lock. The fast-path monitor unlock code checks for
|
||||
// markWord::monitor_value so use markWord::unused_mark which has the
|
||||
// relevant bit set, and also matches ObjectSynchronizer::slow_enter.
|
||||
// relevant bit set, and also matches ObjectSynchronizer::enter.
|
||||
__ mov(tmp, (address)markWord::unused_mark().value());
|
||||
__ str(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes()));
|
||||
|
||||
|
||||
@ -2607,8 +2607,8 @@ void MacroAssembler::biased_locking_exit (Address mark_addr, Register temp_reg,
|
||||
// - Successful Stack-lock: box->dhw == mark.
|
||||
// box->dhw must contain the displaced mark word value
|
||||
// - Failure -- icc.ZFlag == 0 and box->dhw is undefined.
|
||||
// The slow-path fast_enter() and slow_enter() operators
|
||||
// are responsible for setting box->dhw = NonZero (typically markWord::unused_mark()).
|
||||
// The slow-path enter() is responsible for setting
|
||||
// box->dhw = NonZero (typically markWord::unused_mark()).
|
||||
// - Biased: box->dhw is undefined
|
||||
//
|
||||
// SPARC refworkload performance - specifically jetstream and scimark - are
|
||||
|
||||
@ -1620,8 +1620,8 @@ void MacroAssembler::rtm_inflated_locking(Register objReg, Register boxReg, Regi
|
||||
// See also: cmpFastLock and cmpFastUnlock.
|
||||
//
|
||||
// What follows is a specialized inline transliteration of the code
|
||||
// in slow_enter() and slow_exit(). If we're concerned about I$ bloat
|
||||
// another option would be to emit TrySlowEnter and TrySlowExit methods
|
||||
// in enter() and exit(). If we're concerned about I$ bloat another
|
||||
// option would be to emit TrySlowEnter and TrySlowExit methods
|
||||
// at startup-time. These methods would accept arguments as
|
||||
// (rax,=Obj, rbx=Self, rcx=box, rdx=Scratch) and return success-failure
|
||||
// indications in the icc.ZFlag. Fast_Lock and Fast_Unlock would simply
|
||||
|
||||
@ -23,11 +23,12 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zArray.inline.hpp"
|
||||
#include "gc/z/zBackingFile_linux_x86.hpp"
|
||||
#include "gc/z/zBackingPath_linux_x86.hpp"
|
||||
#include "gc/z/zBackingFile_linux.hpp"
|
||||
#include "gc/z/zBackingPath_linux.hpp"
|
||||
#include "gc/z/zErrno.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zLargePages.inline.hpp"
|
||||
#include "gc/z/zSyscall_linux.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
@ -38,7 +39,6 @@
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -46,14 +46,6 @@
|
||||
// Support for building on older Linux systems
|
||||
//
|
||||
|
||||
// System calls
|
||||
#ifndef SYS_fallocate
|
||||
#define SYS_fallocate 285
|
||||
#endif
|
||||
#ifndef SYS_memfd_create
|
||||
#define SYS_memfd_create 319
|
||||
#endif
|
||||
|
||||
// memfd_create(2) flags
|
||||
#ifndef MFD_CLOEXEC
|
||||
#define MFD_CLOEXEC 0x0001U
|
||||
@ -113,14 +105,6 @@ static const char* z_preferred_hugetlbfs_mountpoints[] = {
|
||||
static int z_fallocate_hugetlbfs_attempts = 3;
|
||||
static bool z_fallocate_supported = true;
|
||||
|
||||
static int z_fallocate(int fd, int mode, size_t offset, size_t length) {
|
||||
return syscall(SYS_fallocate, fd, mode, offset, length);
|
||||
}
|
||||
|
||||
static int z_memfd_create(const char *name, unsigned int flags) {
|
||||
return syscall(SYS_memfd_create, name, flags);
|
||||
}
|
||||
|
||||
ZBackingFile::ZBackingFile() :
|
||||
_fd(-1),
|
||||
_size(0),
|
||||
@ -197,7 +181,7 @@ int ZBackingFile::create_mem_fd(const char* name) const {
|
||||
|
||||
// Create file
|
||||
const int extra_flags = ZLargePages::is_explicit() ? MFD_HUGETLB : 0;
|
||||
const int fd = z_memfd_create(filename, MFD_CLOEXEC | extra_flags);
|
||||
const int fd = ZSyscall::memfd_create(filename, MFD_CLOEXEC | extra_flags);
|
||||
if (fd == -1) {
|
||||
ZErrno err;
|
||||
log_debug(gc, init)("Failed to create memfd file (%s)",
|
||||
@ -416,7 +400,7 @@ ZErrno ZBackingFile::fallocate_fill_hole_compat(size_t offset, size_t length) {
|
||||
|
||||
ZErrno ZBackingFile::fallocate_fill_hole_syscall(size_t offset, size_t length) {
|
||||
const int mode = 0; // Allocate
|
||||
const int res = z_fallocate(_fd, mode, offset, length);
|
||||
const int res = ZSyscall::fallocate(_fd, mode, offset, length);
|
||||
if (res == -1) {
|
||||
// Failed
|
||||
return errno;
|
||||
@ -471,7 +455,7 @@ ZErrno ZBackingFile::fallocate_punch_hole(size_t offset, size_t length) {
|
||||
}
|
||||
|
||||
const int mode = FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE;
|
||||
if (z_fallocate(_fd, mode, offset, length) == -1) {
|
||||
if (ZSyscall::fallocate(_fd, mode, offset, length) == -1) {
|
||||
// Failed
|
||||
return errno;
|
||||
}
|
||||
@ -21,8 +21,8 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef OS_CPU_LINUX_X86_GC_Z_ZBACKINGFILE_LINUX_X86_HPP
|
||||
#define OS_CPU_LINUX_X86_GC_Z_ZBACKINGFILE_LINUX_X86_HPP
|
||||
#ifndef OS_LINUX_GC_Z_ZBACKINGFILE_LINUX_HPP
|
||||
#define OS_LINUX_GC_Z_ZBACKINGFILE_LINUX_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
@ -70,4 +70,4 @@ public:
|
||||
size_t uncommit(size_t offset, size_t length);
|
||||
};
|
||||
|
||||
#endif // OS_CPU_LINUX_X86_GC_Z_ZBACKINGFILE_LINUX_X86_HPP
|
||||
#endif // OS_LINUX_GC_Z_ZBACKINGFILE_LINUX_HPP
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zArray.inline.hpp"
|
||||
#include "zBackingPath_linux_aarch64.hpp"
|
||||
#include "gc/z/zBackingPath_linux.hpp"
|
||||
#include "gc/z/zErrno.hpp"
|
||||
#include "logging/log.hpp"
|
||||
|
||||
@ -21,8 +21,8 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef OS_CPU_LINUX_X86_GC_Z_ZBACKINGPATH_LINUX_X86_HPP
|
||||
#define OS_CPU_LINUX_X86_GC_Z_ZBACKINGPATH_LINUX_X86_HPP
|
||||
#ifndef OS_LINUX_GC_Z_ZBACKINGPATH_LINUX_HPP
|
||||
#define OS_LINUX_GC_Z_ZBACKINGPATH_LINUX_HPP
|
||||
|
||||
#include "gc/z/zArray.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
@ -49,4 +49,4 @@ public:
|
||||
const char* get() const;
|
||||
};
|
||||
|
||||
#endif // OS_CPU_LINUX_X86_GC_Z_ZBACKINGPATH_LINUX_X86_HPP
|
||||
#endif // OS_LINUX_GC_Z_ZBACKINGPATH_LINUX_HPP
|
||||
@ -24,6 +24,7 @@
|
||||
#include "gc/z/zErrno.hpp"
|
||||
#include "gc/z/zCPU.hpp"
|
||||
#include "gc/z/zNUMA.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
|
||||
@ -23,15 +23,15 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zAddress.inline.hpp"
|
||||
#include "gc/z/zBackingFile_linux_x86.hpp"
|
||||
#include "gc/z/zErrno.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zLargePages.inline.hpp"
|
||||
#include "gc/z/zMemory.hpp"
|
||||
#include "gc/z/zNUMA.hpp"
|
||||
#include "gc/z/zPhysicalMemory.inline.hpp"
|
||||
#include "gc/z/zPhysicalMemoryBacking_linux_x86.hpp"
|
||||
#include "gc/z/zPhysicalMemoryBacking_linux.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
@ -21,10 +21,10 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef OS_CPU_LINUX_X86_GC_Z_ZPHYSICALMEMORYBACKING_LINUX_X86_HPP
|
||||
#define OS_CPU_LINUX_X86_GC_Z_ZPHYSICALMEMORYBACKING_LINUX_X86_HPP
|
||||
#ifndef OS_LINUX_GC_Z_ZPHYSICALMEMORYBACKING_LINUX_HPP
|
||||
#define OS_LINUX_GC_Z_ZPHYSICALMEMORYBACKING_LINUX_HPP
|
||||
|
||||
#include "gc/z/zBackingFile_linux_x86.hpp"
|
||||
#include "gc/z/zBackingFile_linux.hpp"
|
||||
#include "gc/z/zMemory.hpp"
|
||||
|
||||
class ZErrno;
|
||||
@ -67,4 +67,4 @@ public:
|
||||
void debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const;
|
||||
};
|
||||
|
||||
#endif // OS_CPU_LINUX_X86_GC_Z_ZPHYSICALMEMORYBACKING_LINUX_X86_HPP
|
||||
#endif // OS_LINUX_GC_Z_ZPHYSICALMEMORYBACKING_LINUX_HPP
|
||||
36
src/hotspot/os/linux/gc/z/zSyscall_linux.cpp
Normal file
36
src/hotspot/os/linux/gc/z/zSyscall_linux.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zSyscall_linux.hpp"
|
||||
#include OS_CPU_HEADER(gc/z/zSyscall)
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
int ZSyscall::memfd_create(const char *name, unsigned int flags) {
|
||||
return syscall(SYS_memfd_create, name, flags);
|
||||
}
|
||||
|
||||
int ZSyscall::fallocate(int fd, int mode, size_t offset, size_t length) {
|
||||
return syscall(SYS_fallocate, fd, mode, offset, length);
|
||||
}
|
||||
35
src/hotspot/os/linux/gc/z/zSyscall_linux.hpp
Normal file
35
src/hotspot/os/linux/gc/z/zSyscall_linux.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef OS_LINUX_GC_Z_ZSYSCALL_LINUX_HPP
|
||||
#define OS_LINUX_GC_Z_ZSYSCALL_LINUX_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class ZSyscall : public AllStatic {
|
||||
public:
|
||||
static int memfd_create(const char *name, unsigned int flags);
|
||||
static int fallocate(int fd, int mode, size_t offset, size_t length);
|
||||
};
|
||||
|
||||
#endif // OS_LINUX_GC_Z_ZSYSCALL_LINUX_HPP
|
||||
@ -27,6 +27,7 @@
|
||||
#include <errno.h>
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "osContainer_linux.hpp"
|
||||
@ -673,4 +674,3 @@ int OSContainer::cpu_shares() {
|
||||
|
||||
return shares;
|
||||
}
|
||||
|
||||
|
||||
@ -1,590 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zArray.inline.hpp"
|
||||
#include "gc/z/zBackingFile_linux_aarch64.hpp"
|
||||
#include "gc/z/zBackingPath_linux_aarch64.hpp"
|
||||
#include "gc/z/zErrno.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zLargePages.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//
|
||||
// Support for building on older Linux systems
|
||||
//
|
||||
|
||||
// System calls
|
||||
#ifndef SYS_fallocate
|
||||
#define SYS_fallocate 47
|
||||
#endif
|
||||
#ifndef SYS_memfd_create
|
||||
#define SYS_memfd_create 279
|
||||
#endif
|
||||
|
||||
// memfd_create(2) flags
|
||||
#ifndef MFD_CLOEXEC
|
||||
#define MFD_CLOEXEC 0x0001U
|
||||
#endif
|
||||
#ifndef MFD_HUGETLB
|
||||
#define MFD_HUGETLB 0x0004U
|
||||
#endif
|
||||
|
||||
// open(2) flags
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 02000000
|
||||
#endif
|
||||
#ifndef O_TMPFILE
|
||||
#define O_TMPFILE (020000000 | O_DIRECTORY)
|
||||
#endif
|
||||
|
||||
// fallocate(2) flags
|
||||
#ifndef FALLOC_FL_KEEP_SIZE
|
||||
#define FALLOC_FL_KEEP_SIZE 0x01
|
||||
#endif
|
||||
#ifndef FALLOC_FL_PUNCH_HOLE
|
||||
#define FALLOC_FL_PUNCH_HOLE 0x02
|
||||
#endif
|
||||
|
||||
// Filesystem types, see statfs(2)
|
||||
#ifndef TMPFS_MAGIC
|
||||
#define TMPFS_MAGIC 0x01021994
|
||||
#endif
|
||||
#ifndef HUGETLBFS_MAGIC
|
||||
#define HUGETLBFS_MAGIC 0x958458f6
|
||||
#endif
|
||||
|
||||
// Filesystem names
|
||||
#define ZFILESYSTEM_TMPFS "tmpfs"
|
||||
#define ZFILESYSTEM_HUGETLBFS "hugetlbfs"
|
||||
|
||||
// Sysfs file for transparent huge page on tmpfs
|
||||
#define ZFILENAME_SHMEM_ENABLED "/sys/kernel/mm/transparent_hugepage/shmem_enabled"
|
||||
|
||||
// Java heap filename
|
||||
#define ZFILENAME_HEAP "java_heap"
|
||||
|
||||
// Preferred tmpfs mount points, ordered by priority
|
||||
static const char* z_preferred_tmpfs_mountpoints[] = {
|
||||
"/dev/shm",
|
||||
"/run/shm",
|
||||
NULL
|
||||
};
|
||||
|
||||
// Preferred hugetlbfs mount points, ordered by priority
|
||||
static const char* z_preferred_hugetlbfs_mountpoints[] = {
|
||||
"/dev/hugepages",
|
||||
"/hugepages",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int z_fallocate_hugetlbfs_attempts = 3;
|
||||
static bool z_fallocate_supported = true;
|
||||
|
||||
static int z_fallocate(int fd, int mode, size_t offset, size_t length) {
|
||||
return syscall(SYS_fallocate, fd, mode, offset, length);
|
||||
}
|
||||
|
||||
static int z_memfd_create(const char *name, unsigned int flags) {
|
||||
return syscall(SYS_memfd_create, name, flags);
|
||||
}
|
||||
|
||||
ZBackingFile::ZBackingFile() :
|
||||
_fd(-1),
|
||||
_size(0),
|
||||
_filesystem(0),
|
||||
_block_size(0),
|
||||
_available(0),
|
||||
_initialized(false) {
|
||||
|
||||
// Create backing file
|
||||
_fd = create_fd(ZFILENAME_HEAP);
|
||||
if (_fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get filesystem statistics
|
||||
struct statfs buf;
|
||||
if (fstatfs(_fd, &buf) == -1) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to determine filesystem type for backing file (%s)", err.to_string());
|
||||
return;
|
||||
}
|
||||
|
||||
_filesystem = buf.f_type;
|
||||
_block_size = buf.f_bsize;
|
||||
_available = buf.f_bavail * _block_size;
|
||||
|
||||
// Make sure we're on a supported filesystem
|
||||
if (!is_tmpfs() && !is_hugetlbfs()) {
|
||||
log_error(gc)("Backing file must be located on a %s or a %s filesystem",
|
||||
ZFILESYSTEM_TMPFS, ZFILESYSTEM_HUGETLBFS);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the filesystem type matches requested large page type
|
||||
if (ZLargePages::is_transparent() && !is_tmpfs()) {
|
||||
log_error(gc)("-XX:+UseTransparentHugePages can only be enable when using a %s filesystem",
|
||||
ZFILESYSTEM_TMPFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZLargePages::is_transparent() && !tmpfs_supports_transparent_huge_pages()) {
|
||||
log_error(gc)("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel",
|
||||
ZFILESYSTEM_TMPFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ZLargePages::is_explicit() && !is_hugetlbfs()) {
|
||||
log_error(gc)("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled "
|
||||
"when using a %s filesystem", ZFILESYSTEM_HUGETLBFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ZLargePages::is_explicit() && is_hugetlbfs()) {
|
||||
log_error(gc)("-XX:+UseLargePages must be enabled when using a %s filesystem",
|
||||
ZFILESYSTEM_HUGETLBFS);
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t expected_block_size = is_tmpfs() ? os::vm_page_size() : os::large_page_size();
|
||||
if (expected_block_size != _block_size) {
|
||||
log_error(gc)("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")",
|
||||
is_tmpfs() ? ZFILESYSTEM_TMPFS : ZFILESYSTEM_HUGETLBFS, _block_size, expected_block_size);
|
||||
return;
|
||||
}
|
||||
|
||||
// Successfully initialized
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
int ZBackingFile::create_mem_fd(const char* name) const {
|
||||
// Create file name
|
||||
char filename[PATH_MAX];
|
||||
snprintf(filename, sizeof(filename), "%s%s", name, ZLargePages::is_explicit() ? ".hugetlb" : "");
|
||||
|
||||
// Create file
|
||||
const int extra_flags = ZLargePages::is_explicit() ? MFD_HUGETLB : 0;
|
||||
const int fd = z_memfd_create(filename, MFD_CLOEXEC | extra_flags);
|
||||
if (fd == -1) {
|
||||
ZErrno err;
|
||||
log_debug(gc, init)("Failed to create memfd file (%s)",
|
||||
((ZLargePages::is_explicit() && err == EINVAL) ? "Hugepages not supported" : err.to_string()));
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_info(gc, init)("Heap backed by file: /memfd:%s", filename);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int ZBackingFile::create_file_fd(const char* name) const {
|
||||
const char* const filesystem = ZLargePages::is_explicit()
|
||||
? ZFILESYSTEM_HUGETLBFS
|
||||
: ZFILESYSTEM_TMPFS;
|
||||
const char** const preferred_mountpoints = ZLargePages::is_explicit()
|
||||
? z_preferred_hugetlbfs_mountpoints
|
||||
: z_preferred_tmpfs_mountpoints;
|
||||
|
||||
// Find mountpoint
|
||||
ZBackingPath path(filesystem, preferred_mountpoints);
|
||||
if (path.get() == NULL) {
|
||||
log_error(gc)("Use -XX:ZPath to specify the path to a %s filesystem", filesystem);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Try to create an anonymous file using the O_TMPFILE flag. Note that this
|
||||
// flag requires kernel >= 3.11. If this fails we fall back to open/unlink.
|
||||
const int fd_anon = os::open(path.get(), O_TMPFILE|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
|
||||
if (fd_anon == -1) {
|
||||
ZErrno err;
|
||||
log_debug(gc, init)("Failed to create anonymous file in %s (%s)", path.get(),
|
||||
(err == EINVAL ? "Not supported" : err.to_string()));
|
||||
} else {
|
||||
// Get inode number for anonymous file
|
||||
struct stat stat_buf;
|
||||
if (fstat(fd_anon, &stat_buf) == -1) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to determine inode number for anonymous file (%s)", err.to_string());
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_info(gc, init)("Heap backed by file: %s/#" UINT64_FORMAT, path.get(), (uint64_t)stat_buf.st_ino);
|
||||
|
||||
return fd_anon;
|
||||
}
|
||||
|
||||
log_debug(gc, init)("Falling back to open/unlink");
|
||||
|
||||
// Create file name
|
||||
char filename[PATH_MAX];
|
||||
snprintf(filename, sizeof(filename), "%s/%s.%d", path.get(), name, os::current_process_id());
|
||||
|
||||
// Create file
|
||||
const int fd = os::open(filename, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC, S_IRUSR|S_IWUSR);
|
||||
if (fd == -1) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to create file %s (%s)", filename, err.to_string());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Unlink file
|
||||
if (unlink(filename) == -1) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to unlink file %s (%s)", filename, err.to_string());
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_info(gc, init)("Heap backed by file: %s", filename);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int ZBackingFile::create_fd(const char* name) const {
|
||||
if (ZPath == NULL) {
|
||||
// If the path is not explicitly specified, then we first try to create a memfd file
|
||||
// instead of looking for a tmpfd/hugetlbfs mount point. Note that memfd_create() might
|
||||
// not be supported at all (requires kernel >= 3.17), or it might not support large
|
||||
// pages (requires kernel >= 4.14). If memfd_create() fails, then we try to create a
|
||||
// file on an accessible tmpfs or hugetlbfs mount point.
|
||||
const int fd = create_mem_fd(name);
|
||||
if (fd != -1) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
log_debug(gc, init)("Falling back to searching for an accessible mount point");
|
||||
}
|
||||
|
||||
return create_file_fd(name);
|
||||
}
|
||||
|
||||
bool ZBackingFile::is_initialized() const {
|
||||
return _initialized;
|
||||
}
|
||||
|
||||
int ZBackingFile::fd() const {
|
||||
return _fd;
|
||||
}
|
||||
|
||||
size_t ZBackingFile::size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
size_t ZBackingFile::available() const {
|
||||
return _available;
|
||||
}
|
||||
|
||||
bool ZBackingFile::is_tmpfs() const {
|
||||
return _filesystem == TMPFS_MAGIC;
|
||||
}
|
||||
|
||||
bool ZBackingFile::is_hugetlbfs() const {
|
||||
return _filesystem == HUGETLBFS_MAGIC;
|
||||
}
|
||||
|
||||
bool ZBackingFile::tmpfs_supports_transparent_huge_pages() const {
|
||||
// If the shmem_enabled file exists and is readable then we
|
||||
// know the kernel supports transparent huge pages for tmpfs.
|
||||
return access(ZFILENAME_SHMEM_ENABLED, R_OK) == 0;
|
||||
}
|
||||
|
||||
ZErrno ZBackingFile::fallocate_compat_ftruncate(size_t size) const {
|
||||
while (ftruncate(_fd, size) == -1) {
|
||||
if (errno != EINTR) {
|
||||
// Failed
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZBackingFile::fallocate_compat_mmap(size_t offset, size_t length, bool touch) const {
|
||||
// On hugetlbfs, mapping a file segment will fail immediately, without
|
||||
// the need to touch the mapped pages first, if there aren't enough huge
|
||||
// pages available to back the mapping.
|
||||
void* const addr = mmap(0, length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, offset);
|
||||
if (addr == MAP_FAILED) {
|
||||
// Failed
|
||||
return errno;
|
||||
}
|
||||
|
||||
// Once mapped, the huge pages are only reserved. We need to touch them
|
||||
// to associate them with the file segment. Note that we can not punch
|
||||
// hole in file segments which only have reserved pages.
|
||||
if (touch) {
|
||||
char* const start = (char*)addr;
|
||||
char* const end = start + length;
|
||||
os::pretouch_memory(start, end, _block_size);
|
||||
}
|
||||
|
||||
// Unmap again. From now on, the huge pages that were mapped are allocated
|
||||
// to this file. There's no risk in getting SIGBUS when touching them.
|
||||
if (munmap(addr, length) == -1) {
|
||||
// Failed
|
||||
return errno;
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZBackingFile::fallocate_compat_pwrite(size_t offset, size_t length) const {
|
||||
uint8_t data = 0;
|
||||
|
||||
// Allocate backing memory by writing to each block
|
||||
for (size_t pos = offset; pos < offset + length; pos += _block_size) {
|
||||
if (pwrite(_fd, &data, sizeof(data), pos) == -1) {
|
||||
// Failed
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZBackingFile::fallocate_fill_hole_compat(size_t offset, size_t length) {
|
||||
// fallocate(2) is only supported by tmpfs since Linux 3.5, and by hugetlbfs
|
||||
// since Linux 4.3. When fallocate(2) is not supported we emulate it using
|
||||
// ftruncate/pwrite (for tmpfs) or ftruncate/mmap/munmap (for hugetlbfs).
|
||||
|
||||
const size_t end = offset + length;
|
||||
if (end > _size) {
|
||||
// Increase file size
|
||||
const ZErrno err = fallocate_compat_ftruncate(end);
|
||||
if (err) {
|
||||
// Failed
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate backing memory
|
||||
const ZErrno err = is_hugetlbfs() ? fallocate_compat_mmap(offset, length, false /* touch */)
|
||||
: fallocate_compat_pwrite(offset, length);
|
||||
if (err) {
|
||||
if (end > _size) {
|
||||
// Restore file size
|
||||
fallocate_compat_ftruncate(_size);
|
||||
}
|
||||
|
||||
// Failed
|
||||
return err;
|
||||
}
|
||||
|
||||
if (end > _size) {
|
||||
// Record new file size
|
||||
_size = end;
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZBackingFile::fallocate_fill_hole_syscall(size_t offset, size_t length) {
|
||||
const int mode = 0; // Allocate
|
||||
const int res = z_fallocate(_fd, mode, offset, length);
|
||||
if (res == -1) {
|
||||
// Failed
|
||||
return errno;
|
||||
}
|
||||
|
||||
const size_t end = offset + length;
|
||||
if (end > _size) {
|
||||
// Record new file size
|
||||
_size = end;
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZBackingFile::fallocate_fill_hole(size_t offset, size_t length) {
|
||||
// Using compat mode is more efficient when allocating space on hugetlbfs.
|
||||
// Note that allocating huge pages this way will only reserve them, and not
|
||||
// associate them with segments of the file. We must guarantee that we at
|
||||
// some point touch these segments, otherwise we can not punch hole in them.
|
||||
if (z_fallocate_supported && !is_hugetlbfs()) {
|
||||
const ZErrno err = fallocate_fill_hole_syscall(offset, length);
|
||||
if (!err) {
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err != ENOSYS && err != EOPNOTSUPP) {
|
||||
// Failed
|
||||
return err;
|
||||
}
|
||||
|
||||
// Not supported
|
||||
log_debug(gc)("Falling back to fallocate() compatibility mode");
|
||||
z_fallocate_supported = false;
|
||||
}
|
||||
|
||||
return fallocate_fill_hole_compat(offset, length);
|
||||
}
|
||||
|
||||
ZErrno ZBackingFile::fallocate_punch_hole(size_t offset, size_t length) {
|
||||
if (is_hugetlbfs()) {
|
||||
// We can only punch hole in pages that have been touched. Non-touched
|
||||
// pages are only reserved, and not associated with any specific file
|
||||
// segment. We don't know which pages have been previously touched, so
|
||||
// we always touch them here to guarantee that we can punch hole.
|
||||
const ZErrno err = fallocate_compat_mmap(offset, length, true /* touch */);
|
||||
if (err) {
|
||||
// Failed
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
const int mode = FALLOC_FL_PUNCH_HOLE|FALLOC_FL_KEEP_SIZE;
|
||||
if (z_fallocate(_fd, mode, offset, length) == -1) {
|
||||
// Failed
|
||||
return errno;
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZBackingFile::split_and_fallocate(bool punch_hole, size_t offset, size_t length) {
|
||||
// Try first half
|
||||
const size_t offset0 = offset;
|
||||
const size_t length0 = align_up(length / 2, _block_size);
|
||||
const ZErrno err0 = fallocate(punch_hole, offset0, length0);
|
||||
if (err0) {
|
||||
return err0;
|
||||
}
|
||||
|
||||
// Try second half
|
||||
const size_t offset1 = offset0 + length0;
|
||||
const size_t length1 = length - length0;
|
||||
const ZErrno err1 = fallocate(punch_hole, offset1, length1);
|
||||
if (err1) {
|
||||
return err1;
|
||||
}
|
||||
|
||||
// Success
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZErrno ZBackingFile::fallocate(bool punch_hole, size_t offset, size_t length) {
|
||||
assert(is_aligned(offset, _block_size), "Invalid offset");
|
||||
assert(is_aligned(length, _block_size), "Invalid length");
|
||||
|
||||
const ZErrno err = punch_hole ? fallocate_punch_hole(offset, length) : fallocate_fill_hole(offset, length);
|
||||
if (err == EINTR && length > _block_size) {
|
||||
// Calling fallocate(2) with a large length can take a long time to
|
||||
// complete. When running profilers, such as VTune, this syscall will
|
||||
// be constantly interrupted by signals. Expanding the file in smaller
|
||||
// steps avoids this problem.
|
||||
return split_and_fallocate(punch_hole, offset, length);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
bool ZBackingFile::commit_inner(size_t offset, size_t length) {
|
||||
log_trace(gc, heap)("Committing memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)",
|
||||
offset / M, (offset + length) / M, length / M);
|
||||
|
||||
retry:
|
||||
const ZErrno err = fallocate(false /* punch_hole */, offset, length);
|
||||
if (err) {
|
||||
if (err == ENOSPC && !is_init_completed() && is_hugetlbfs() && z_fallocate_hugetlbfs_attempts-- > 0) {
|
||||
// If we fail to allocate during initialization, due to lack of space on
|
||||
// the hugetlbfs filesystem, then we wait and retry a few times before
|
||||
// giving up. Otherwise there is a risk that running JVMs back-to-back
|
||||
// will fail, since there is a delay between process termination and the
|
||||
// huge pages owned by that process being returned to the huge page pool
|
||||
// and made available for new allocations.
|
||||
log_debug(gc, init)("Failed to commit memory (%s), retrying", err.to_string());
|
||||
|
||||
// Wait and retry in one second, in the hope that huge pages will be
|
||||
// available by then.
|
||||
sleep(1);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
// Failed
|
||||
log_error(gc)("Failed to commit memory (%s)", err.to_string());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t ZBackingFile::commit(size_t offset, size_t length) {
|
||||
// Try to commit the whole region
|
||||
if (commit_inner(offset, length)) {
|
||||
// Success
|
||||
return length;
|
||||
}
|
||||
|
||||
// Failed, try to commit as much as possible
|
||||
size_t start = offset;
|
||||
size_t end = offset + length;
|
||||
|
||||
for (;;) {
|
||||
length = align_down((end - start) / 2, ZGranuleSize);
|
||||
if (length < ZGranuleSize) {
|
||||
// Done, don't commit more
|
||||
return start - offset;
|
||||
}
|
||||
|
||||
if (commit_inner(start, length)) {
|
||||
// Success, try commit more
|
||||
start += length;
|
||||
} else {
|
||||
// Failed, try commit less
|
||||
end -= length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t ZBackingFile::uncommit(size_t offset, size_t length) {
|
||||
log_trace(gc, heap)("Uncommitting memory: " SIZE_FORMAT "M-" SIZE_FORMAT "M (" SIZE_FORMAT "M)",
|
||||
offset / M, (offset + length) / M, length / M);
|
||||
|
||||
const ZErrno err = fallocate(true /* punch_hole */, offset, length);
|
||||
if (err) {
|
||||
log_error(gc)("Failed to uncommit memory (%s)", err.to_string());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef OS_CPU_LINUX_AARCH64_GC_Z_ZBACKINGFILE_LINUX_AARCH64_HPP
|
||||
#define OS_CPU_LINUX_AARCH64_GC_Z_ZBACKINGFILE_LINUX_AARCH64_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class ZErrno;
|
||||
|
||||
class ZBackingFile {
|
||||
private:
|
||||
int _fd;
|
||||
size_t _size;
|
||||
uint64_t _filesystem;
|
||||
size_t _block_size;
|
||||
size_t _available;
|
||||
bool _initialized;
|
||||
|
||||
int create_mem_fd(const char* name) const;
|
||||
int create_file_fd(const char* name) const;
|
||||
int create_fd(const char* name) const;
|
||||
|
||||
bool is_tmpfs() const;
|
||||
bool is_hugetlbfs() const;
|
||||
bool tmpfs_supports_transparent_huge_pages() const;
|
||||
|
||||
ZErrno fallocate_compat_ftruncate(size_t size) const;
|
||||
ZErrno fallocate_compat_mmap(size_t offset, size_t length, bool reserve_only) const;
|
||||
ZErrno fallocate_compat_pwrite(size_t offset, size_t length) const;
|
||||
ZErrno fallocate_fill_hole_compat(size_t offset, size_t length);
|
||||
ZErrno fallocate_fill_hole_syscall(size_t offset, size_t length);
|
||||
ZErrno fallocate_fill_hole(size_t offset, size_t length);
|
||||
ZErrno fallocate_punch_hole(size_t offset, size_t length);
|
||||
ZErrno split_and_fallocate(bool punch_hole, size_t offset, size_t length);
|
||||
ZErrno fallocate(bool punch_hole, size_t offset, size_t length);
|
||||
|
||||
bool commit_inner(size_t offset, size_t length);
|
||||
|
||||
public:
|
||||
ZBackingFile();
|
||||
|
||||
bool is_initialized() const;
|
||||
|
||||
int fd() const;
|
||||
size_t size() const;
|
||||
size_t available() const;
|
||||
|
||||
size_t commit(size_t offset, size_t length);
|
||||
size_t uncommit(size_t offset, size_t length);
|
||||
};
|
||||
|
||||
#endif // OS_CPU_LINUX_AARCH64_GC_Z_ZBACKINGFILE_LINUX_AARCH64_HPP
|
||||
@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef OS_CPU_LINUX_AARCH64_GC_Z_ZBACKINGPATH_LINUX_AARCH64_HPP
|
||||
#define OS_CPU_LINUX_AARCH64_GC_Z_ZBACKINGPATH_LINUX_AARCH64_HPP
|
||||
|
||||
#include "gc/z/zArray.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class ZBackingPath : public StackObj {
|
||||
private:
|
||||
char* _path;
|
||||
|
||||
char* get_mountpoint(const char* line,
|
||||
const char* filesystem) const;
|
||||
void get_mountpoints(const char* filesystem,
|
||||
ZArray<char*>* mountpoints) const;
|
||||
void free_mountpoints(ZArray<char*>* mountpoints) const;
|
||||
char* find_preferred_mountpoint(const char* filesystem,
|
||||
ZArray<char*>* mountpoints,
|
||||
const char** preferred_mountpoints) const;
|
||||
char* find_mountpoint(const char* filesystem,
|
||||
const char** preferred_mountpoints) const;
|
||||
|
||||
public:
|
||||
ZBackingPath(const char* filesystem, const char** preferred_mountpoints);
|
||||
~ZBackingPath();
|
||||
|
||||
const char* get() const;
|
||||
};
|
||||
|
||||
#endif // OS_CPU_LINUX_AARCH64_GC_Z_ZBACKINGPATH_LINUX_AARCH64_HPP
|
||||
@ -1,333 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zAddress.inline.hpp"
|
||||
#include "gc/z/zBackingFile_linux_aarch64.hpp"
|
||||
#include "gc/z/zErrno.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
#include "gc/z/zLargePages.inline.hpp"
|
||||
#include "gc/z/zMemory.hpp"
|
||||
#include "gc/z/zNUMA.hpp"
|
||||
#include "gc/z/zPhysicalMemory.inline.hpp"
|
||||
#include "gc/z/zPhysicalMemoryBacking_linux_aarch64.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/init.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
//
|
||||
// Support for building on older Linux systems
|
||||
//
|
||||
|
||||
// madvise(2) flags
|
||||
#ifndef MADV_HUGEPAGE
|
||||
#define MADV_HUGEPAGE 14
|
||||
#endif
|
||||
|
||||
// Proc file entry for max map mount
|
||||
#define ZFILENAME_PROC_MAX_MAP_COUNT "/proc/sys/vm/max_map_count"
|
||||
|
||||
bool ZPhysicalMemoryBacking::is_initialized() const {
|
||||
return _file.is_initialized();
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::warn_available_space(size_t max) const {
|
||||
// Note that the available space on a tmpfs or a hugetlbfs filesystem
|
||||
// will be zero if no size limit was specified when it was mounted.
|
||||
const size_t available = _file.available();
|
||||
if (available == 0) {
|
||||
// No size limit set, skip check
|
||||
log_info(gc, init)("Available space on backing filesystem: N/A");
|
||||
return;
|
||||
}
|
||||
|
||||
log_info(gc, init)("Available space on backing filesystem: " SIZE_FORMAT "M", available / M);
|
||||
|
||||
// Warn if the filesystem doesn't currently have enough space available to hold
|
||||
// the max heap size. The max heap size will be capped if we later hit this limit
|
||||
// when trying to expand the heap.
|
||||
if (available < max) {
|
||||
log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
|
||||
log_warning(gc)("Not enough space available on the backing filesystem to hold the current max Java heap");
|
||||
log_warning(gc)("size (" SIZE_FORMAT "M). Please adjust the size of the backing filesystem accordingly "
|
||||
"(available", max / M);
|
||||
log_warning(gc)("space is currently " SIZE_FORMAT "M). Continuing execution with the current filesystem "
|
||||
"size could", available / M);
|
||||
log_warning(gc)("lead to a premature OutOfMemoryError being thrown, due to failure to map memory.");
|
||||
}
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::warn_max_map_count(size_t max) const {
|
||||
const char* const filename = ZFILENAME_PROC_MAX_MAP_COUNT;
|
||||
FILE* const file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
// Failed to open file, skip check
|
||||
log_debug(gc, init)("Failed to open %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t actual_max_map_count = 0;
|
||||
const int result = fscanf(file, SIZE_FORMAT, &actual_max_map_count);
|
||||
fclose(file);
|
||||
if (result != 1) {
|
||||
// Failed to read file, skip check
|
||||
log_debug(gc, init)("Failed to read %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
// The required max map count is impossible to calculate exactly since subsystems
|
||||
// other than ZGC are also creating memory mappings, and we have no control over that.
|
||||
// However, ZGC tends to create the most mappings and dominate the total count.
|
||||
// In the worst cases, ZGC will map each granule three times, i.e. once per heap view.
|
||||
// We speculate that we need another 20% to allow for non-ZGC subsystems to map memory.
|
||||
const size_t required_max_map_count = (max / ZGranuleSize) * 3 * 1.2;
|
||||
if (actual_max_map_count < required_max_map_count) {
|
||||
log_warning(gc)("***** WARNING! INCORRECT SYSTEM CONFIGURATION DETECTED! *****");
|
||||
log_warning(gc)("The system limit on number of memory mappings per process might be too low for the given");
|
||||
log_warning(gc)("max Java heap size (" SIZE_FORMAT "M). Please adjust %s to allow for at",
|
||||
max / M, filename);
|
||||
log_warning(gc)("least " SIZE_FORMAT " mappings (current limit is " SIZE_FORMAT "). Continuing execution "
|
||||
"with the current", required_max_map_count, actual_max_map_count);
|
||||
log_warning(gc)("limit could lead to a fatal error, due to failure to map memory.");
|
||||
}
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::warn_commit_limits(size_t max) const {
|
||||
// Warn if available space is too low
|
||||
warn_available_space(max);
|
||||
|
||||
// Warn if max map count is too low
|
||||
warn_max_map_count(max);
|
||||
}
|
||||
|
||||
bool ZPhysicalMemoryBacking::supports_uncommit() {
|
||||
assert(!is_init_completed(), "Invalid state");
|
||||
assert(_file.size() >= ZGranuleSize, "Invalid size");
|
||||
|
||||
// Test if uncommit is supported by uncommitting and then re-committing a granule
|
||||
return commit(uncommit(ZGranuleSize)) == ZGranuleSize;
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::commit(size_t size) {
|
||||
size_t committed = 0;
|
||||
|
||||
// Fill holes in the backing file
|
||||
while (committed < size) {
|
||||
size_t allocated = 0;
|
||||
const size_t remaining = size - committed;
|
||||
const uintptr_t start = _uncommitted.alloc_from_front_at_most(remaining, &allocated);
|
||||
if (start == UINTPTR_MAX) {
|
||||
// No holes to commit
|
||||
break;
|
||||
}
|
||||
|
||||
// Try commit hole
|
||||
const size_t filled = _file.commit(start, allocated);
|
||||
if (filled > 0) {
|
||||
// Successful or partialy successful
|
||||
_committed.free(start, filled);
|
||||
committed += filled;
|
||||
}
|
||||
if (filled < allocated) {
|
||||
// Failed or partialy failed
|
||||
_uncommitted.free(start + filled, allocated - filled);
|
||||
return committed;
|
||||
}
|
||||
}
|
||||
|
||||
// Expand backing file
|
||||
if (committed < size) {
|
||||
const size_t remaining = size - committed;
|
||||
const uintptr_t start = _file.size();
|
||||
const size_t expanded = _file.commit(start, remaining);
|
||||
if (expanded > 0) {
|
||||
// Successful or partialy successful
|
||||
_committed.free(start, expanded);
|
||||
committed += expanded;
|
||||
}
|
||||
}
|
||||
|
||||
return committed;
|
||||
}
|
||||
|
||||
size_t ZPhysicalMemoryBacking::uncommit(size_t size) {
|
||||
size_t uncommitted = 0;
|
||||
|
||||
// Punch holes in backing file
|
||||
while (uncommitted < size) {
|
||||
size_t allocated = 0;
|
||||
const size_t remaining = size - uncommitted;
|
||||
const uintptr_t start = _committed.alloc_from_back_at_most(remaining, &allocated);
|
||||
assert(start != UINTPTR_MAX, "Allocation should never fail");
|
||||
|
||||
// Try punch hole
|
||||
const size_t punched = _file.uncommit(start, allocated);
|
||||
if (punched > 0) {
|
||||
// Successful or partialy successful
|
||||
_uncommitted.free(start, punched);
|
||||
uncommitted += punched;
|
||||
}
|
||||
if (punched < allocated) {
|
||||
// Failed or partialy failed
|
||||
_committed.free(start + punched, allocated - punched);
|
||||
return uncommitted;
|
||||
}
|
||||
}
|
||||
|
||||
return uncommitted;
|
||||
}
|
||||
|
||||
ZPhysicalMemory ZPhysicalMemoryBacking::alloc(size_t size) {
|
||||
assert(is_aligned(size, ZGranuleSize), "Invalid size");
|
||||
|
||||
ZPhysicalMemory pmem;
|
||||
|
||||
// Allocate segments
|
||||
for (size_t allocated = 0; allocated < size; allocated += ZGranuleSize) {
|
||||
const uintptr_t start = _committed.alloc_from_front(ZGranuleSize);
|
||||
assert(start != UINTPTR_MAX, "Allocation should never fail");
|
||||
pmem.add_segment(ZPhysicalMemorySegment(start, ZGranuleSize));
|
||||
}
|
||||
|
||||
return pmem;
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::free(const ZPhysicalMemory& pmem) {
|
||||
const size_t nsegments = pmem.nsegments();
|
||||
|
||||
// Free segments
|
||||
for (size_t i = 0; i < nsegments; i++) {
|
||||
const ZPhysicalMemorySegment& segment = pmem.segment(i);
|
||||
_committed.free(segment.start(), segment.size());
|
||||
}
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::map_failed(ZErrno err) const {
|
||||
if (err == ENOMEM) {
|
||||
fatal("Failed to map memory. Please check the system limit on number of "
|
||||
"memory mappings allowed per process (see %s)", ZFILENAME_PROC_MAX_MAP_COUNT);
|
||||
} else {
|
||||
fatal("Failed to map memory (%s)", err.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::advise_view(uintptr_t addr, size_t size, int advice) const {
|
||||
if (madvise((void*)addr, size, advice) == -1) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to advise on memory (advice %d, %s)", advice, err.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::pretouch_view(uintptr_t addr, size_t size) const {
|
||||
const size_t page_size = ZLargePages::is_explicit() ? os::large_page_size() : os::vm_page_size();
|
||||
os::pretouch_memory((void*)addr, (void*)(addr + size), page_size);
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const {
|
||||
const size_t nsegments = pmem.nsegments();
|
||||
size_t size = 0;
|
||||
|
||||
// Map segments
|
||||
for (size_t i = 0; i < nsegments; i++) {
|
||||
const ZPhysicalMemorySegment& segment = pmem.segment(i);
|
||||
const uintptr_t segment_addr = addr + size;
|
||||
const void* const res = mmap((void*)segment_addr, segment.size(), PROT_READ|PROT_WRITE, MAP_FIXED|MAP_SHARED, _file.fd(), segment.start());
|
||||
if (res == MAP_FAILED) {
|
||||
ZErrno err;
|
||||
map_failed(err);
|
||||
}
|
||||
|
||||
size += segment.size();
|
||||
}
|
||||
|
||||
// Advise on use of transparent huge pages before touching it
|
||||
if (ZLargePages::is_transparent()) {
|
||||
advise_view(addr, size, MADV_HUGEPAGE);
|
||||
}
|
||||
|
||||
// NUMA interleave memory before touching it
|
||||
ZNUMA::memory_interleave(addr, size);
|
||||
|
||||
// Pre-touch memory
|
||||
if (pretouch) {
|
||||
pretouch_view(addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const {
|
||||
// Note that we must keep the address space reservation intact and just detach
|
||||
// the backing memory. For this reason we map a new anonymous, non-accessible
|
||||
// and non-reserved page over the mapping instead of actually unmapping.
|
||||
const void* const res = mmap((void*)addr, pmem.size(), PROT_NONE, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
|
||||
if (res == MAP_FAILED) {
|
||||
ZErrno err;
|
||||
map_failed(err);
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t ZPhysicalMemoryBacking::nmt_address(uintptr_t offset) const {
|
||||
// From an NMT point of view we treat the first heap view (marked0) as committed
|
||||
return ZAddress::marked0(offset);
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::map(const ZPhysicalMemory& pmem, uintptr_t offset) const {
|
||||
if (ZVerifyViews) {
|
||||
// Map good view
|
||||
map_view(pmem, ZAddress::good(offset), AlwaysPreTouch);
|
||||
} else {
|
||||
// Map all views
|
||||
map_view(pmem, ZAddress::marked0(offset), AlwaysPreTouch);
|
||||
map_view(pmem, ZAddress::marked1(offset), AlwaysPreTouch);
|
||||
map_view(pmem, ZAddress::remapped(offset), AlwaysPreTouch);
|
||||
}
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const {
|
||||
if (ZVerifyViews) {
|
||||
// Unmap good view
|
||||
unmap_view(pmem, ZAddress::good(offset));
|
||||
} else {
|
||||
// Unmap all views
|
||||
unmap_view(pmem, ZAddress::marked0(offset));
|
||||
unmap_view(pmem, ZAddress::marked1(offset));
|
||||
unmap_view(pmem, ZAddress::remapped(offset));
|
||||
}
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const {
|
||||
// Map good view
|
||||
assert(ZVerifyViews, "Should be enabled");
|
||||
map_view(pmem, ZAddress::good(offset), false /* pretouch */);
|
||||
}
|
||||
|
||||
void ZPhysicalMemoryBacking::debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const {
|
||||
// Unmap good view
|
||||
assert(ZVerifyViews, "Should be enabled");
|
||||
unmap_view(pmem, ZAddress::good(offset));
|
||||
}
|
||||
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef OS_CPU_LINUX_AARCH64_GC_Z_ZPHYSICALMEMORYBACKING_LINUX_AARCH64_HPP
|
||||
#define OS_CPU_LINUX_AARCH64_GC_Z_ZPHYSICALMEMORYBACKING_LINUX_AARCH64_HPP
|
||||
|
||||
#include "gc/z/zBackingFile_linux_aarch64.hpp"
|
||||
#include "gc/z/zMemory.hpp"
|
||||
|
||||
class ZErrno;
|
||||
class ZPhysicalMemory;
|
||||
|
||||
class ZPhysicalMemoryBacking {
|
||||
private:
|
||||
ZBackingFile _file;
|
||||
ZMemoryManager _committed;
|
||||
ZMemoryManager _uncommitted;
|
||||
|
||||
void warn_available_space(size_t max) const;
|
||||
void warn_max_map_count(size_t max) const;
|
||||
|
||||
void map_failed(ZErrno err) const;
|
||||
|
||||
void advise_view(uintptr_t addr, size_t size, int advice) const;
|
||||
void pretouch_view(uintptr_t addr, size_t size) const;
|
||||
void map_view(const ZPhysicalMemory& pmem, uintptr_t addr, bool pretouch) const;
|
||||
void unmap_view(const ZPhysicalMemory& pmem, uintptr_t addr) const;
|
||||
|
||||
public:
|
||||
bool is_initialized() const;
|
||||
|
||||
void warn_commit_limits(size_t max) const;
|
||||
bool supports_uncommit();
|
||||
|
||||
size_t commit(size_t size);
|
||||
size_t uncommit(size_t size);
|
||||
|
||||
ZPhysicalMemory alloc(size_t size);
|
||||
void free(const ZPhysicalMemory& pmem);
|
||||
|
||||
uintptr_t nmt_address(uintptr_t offset) const;
|
||||
|
||||
void map(const ZPhysicalMemory& pmem, uintptr_t offset) const;
|
||||
void unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const;
|
||||
|
||||
void debug_map(const ZPhysicalMemory& pmem, uintptr_t offset) const;
|
||||
void debug_unmap(const ZPhysicalMemory& pmem, uintptr_t offset) const;
|
||||
};
|
||||
|
||||
#endif // OS_CPU_LINUX_AARCH64_GC_Z_ZPHYSICALMEMORYBACKING_LINUX_AARCH64_HPP
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef OS_CPU_LINUX_AARCH64_GC_Z_ZSYSCALL_LINUX_AARCH64_HPP
|
||||
#define OS_CPU_LINUX_AARCH64_GC_Z_ZSYSCALL_LINUX_AARCH64_HPP
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
//
|
||||
// Support for building on older Linux systems
|
||||
//
|
||||
|
||||
#ifndef SYS_memfd_create
|
||||
#define SYS_memfd_create 279
|
||||
#endif
|
||||
#ifndef SYS_fallocate
|
||||
#define SYS_fallocate 47
|
||||
#endif
|
||||
|
||||
#endif // OS_CPU_LINUX_AARCH64_GC_Z_ZSYSCALL_LINUX_AARCH64_HPP
|
||||
@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/z/zArray.inline.hpp"
|
||||
#include "gc/z/zBackingPath_linux_x86.hpp"
|
||||
#include "gc/z/zErrno.hpp"
|
||||
#include "logging/log.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Mount information, see proc(5) for more details.
|
||||
#define PROC_SELF_MOUNTINFO "/proc/self/mountinfo"
|
||||
|
||||
ZBackingPath::ZBackingPath(const char* filesystem, const char** preferred_mountpoints) {
|
||||
if (ZPath != NULL) {
|
||||
// Use specified path
|
||||
_path = strdup(ZPath);
|
||||
} else {
|
||||
// Find suitable path
|
||||
_path = find_mountpoint(filesystem, preferred_mountpoints);
|
||||
}
|
||||
}
|
||||
|
||||
ZBackingPath::~ZBackingPath() {
|
||||
free(_path);
|
||||
_path = NULL;
|
||||
}
|
||||
|
||||
char* ZBackingPath::get_mountpoint(const char* line, const char* filesystem) const {
|
||||
char* line_mountpoint = NULL;
|
||||
char* line_filesystem = NULL;
|
||||
|
||||
// Parse line and return a newly allocated string containing the mount point if
|
||||
// the line contains a matching filesystem and the mount point is accessible by
|
||||
// the current user.
|
||||
if (sscanf(line, "%*u %*u %*u:%*u %*s %ms %*[^-]- %ms", &line_mountpoint, &line_filesystem) != 2 ||
|
||||
strcmp(line_filesystem, filesystem) != 0 ||
|
||||
access(line_mountpoint, R_OK|W_OK|X_OK) != 0) {
|
||||
// Not a matching or accessible filesystem
|
||||
free(line_mountpoint);
|
||||
line_mountpoint = NULL;
|
||||
}
|
||||
|
||||
free(line_filesystem);
|
||||
|
||||
return line_mountpoint;
|
||||
}
|
||||
|
||||
void ZBackingPath::get_mountpoints(const char* filesystem, ZArray<char*>* mountpoints) const {
|
||||
FILE* fd = fopen(PROC_SELF_MOUNTINFO, "r");
|
||||
if (fd == NULL) {
|
||||
ZErrno err;
|
||||
log_error(gc)("Failed to open %s: %s", PROC_SELF_MOUNTINFO, err.to_string());
|
||||
return;
|
||||
}
|
||||
|
||||
char* line = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
while (getline(&line, &length, fd) != -1) {
|
||||
char* const mountpoint = get_mountpoint(line, filesystem);
|
||||
if (mountpoint != NULL) {
|
||||
mountpoints->add(mountpoint);
|
||||
}
|
||||
}
|
||||
|
||||
free(line);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
void ZBackingPath::free_mountpoints(ZArray<char*>* mountpoints) const {
|
||||
ZArrayIterator<char*> iter(mountpoints);
|
||||
for (char* mountpoint; iter.next(&mountpoint);) {
|
||||
free(mountpoint);
|
||||
}
|
||||
mountpoints->clear();
|
||||
}
|
||||
|
||||
char* ZBackingPath::find_preferred_mountpoint(const char* filesystem,
|
||||
ZArray<char*>* mountpoints,
|
||||
const char** preferred_mountpoints) const {
|
||||
// Find preferred mount point
|
||||
ZArrayIterator<char*> iter1(mountpoints);
|
||||
for (char* mountpoint; iter1.next(&mountpoint);) {
|
||||
for (const char** preferred = preferred_mountpoints; *preferred != NULL; preferred++) {
|
||||
if (!strcmp(mountpoint, *preferred)) {
|
||||
// Preferred mount point found
|
||||
return strdup(mountpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preferred mount point not found
|
||||
log_error(gc)("More than one %s filesystem found:", filesystem);
|
||||
ZArrayIterator<char*> iter2(mountpoints);
|
||||
for (char* mountpoint; iter2.next(&mountpoint);) {
|
||||
log_error(gc)(" %s", mountpoint);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* ZBackingPath::find_mountpoint(const char* filesystem, const char** preferred_mountpoints) const {
|
||||
char* path = NULL;
|
||||
ZArray<char*> mountpoints;
|
||||
|
||||
get_mountpoints(filesystem, &mountpoints);
|
||||
|
||||
if (mountpoints.size() == 0) {
|
||||
// No mount point found
|
||||
log_error(gc)("Failed to find an accessible %s filesystem", filesystem);
|
||||
} else if (mountpoints.size() == 1) {
|
||||
// One mount point found
|
||||
path = strdup(mountpoints.at(0));
|
||||
} else {
|
||||
// More than one mount point found
|
||||
path = find_preferred_mountpoint(filesystem, &mountpoints, preferred_mountpoints);
|
||||
}
|
||||
|
||||
free_mountpoints(&mountpoints);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
const char* ZBackingPath::get() const {
|
||||
return _path;
|
||||
}
|
||||
40
src/hotspot/os_cpu/linux_x86/gc/z/zSyscall_linux_x86.hpp
Normal file
40
src/hotspot/os_cpu/linux_x86/gc/z/zSyscall_linux_x86.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#ifndef OS_CPU_LINUX_X86_GC_Z_ZSYSCALL_LINUX_X86_HPP
|
||||
#define OS_CPU_LINUX_X86_GC_Z_ZSYSCALL_LINUX_X86_HPP
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
//
|
||||
// Support for building on older Linux systems
|
||||
//
|
||||
|
||||
#ifndef SYS_memfd_create
|
||||
#define SYS_memfd_create 319
|
||||
#endif
|
||||
#ifndef SYS_fallocate
|
||||
#define SYS_fallocate 285
|
||||
#endif
|
||||
|
||||
#endif // OS_CPU_LINUX_X86_GC_Z_ZSYSCALL_LINUX_X86_HPP
|
||||
@ -705,19 +705,11 @@ JRT_ENTRY_NO_ASYNC(void, Runtime1::monitorenter(JavaThread* thread, oopDesc* obj
|
||||
Atomic::inc(BiasedLocking::slow_path_entry_count_addr());
|
||||
}
|
||||
Handle h_obj(thread, obj);
|
||||
if (UseBiasedLocking) {
|
||||
// Retry fast entry if bias is revoked to avoid unnecessary inflation
|
||||
ObjectSynchronizer::fast_enter(h_obj, lock->lock(), true, CHECK);
|
||||
} else {
|
||||
if (UseFastLocking) {
|
||||
// When using fast locking, the compiled code has already tried the fast case
|
||||
assert(obj == lock->obj(), "must match");
|
||||
ObjectSynchronizer::slow_enter(h_obj, lock->lock(), THREAD);
|
||||
} else {
|
||||
lock->set_obj(obj);
|
||||
ObjectSynchronizer::fast_enter(h_obj, lock->lock(), false, THREAD);
|
||||
}
|
||||
if (!UseFastLocking) {
|
||||
lock->set_obj(obj);
|
||||
}
|
||||
assert(obj == lock->obj(), "must match");
|
||||
ObjectSynchronizer::enter(h_obj, lock->lock(), THREAD);
|
||||
JRT_END
|
||||
|
||||
|
||||
@ -730,12 +722,7 @@ JRT_LEAF(void, Runtime1::monitorexit(JavaThread* thread, BasicObjectLock* lock))
|
||||
|
||||
oop obj = lock->obj();
|
||||
assert(oopDesc::is_oop(obj), "must be NULL or an object");
|
||||
if (UseFastLocking) {
|
||||
// When using fast locking, the compiled code has already tried the fast case
|
||||
ObjectSynchronizer::slow_exit(obj, lock->lock(), THREAD);
|
||||
} else {
|
||||
ObjectSynchronizer::fast_exit(obj, lock->lock(), THREAD);
|
||||
}
|
||||
ObjectSynchronizer::exit(obj, lock->lock(), THREAD);
|
||||
JRT_END
|
||||
|
||||
// Cf. OptoRuntime::deoptimize_caller_frame
|
||||
|
||||
@ -69,12 +69,10 @@
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "services/management.hpp"
|
||||
#include "services/threadService.hpp"
|
||||
#include "utilities/classpathStream.hpp"
|
||||
#include "utilities/events.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_CDS
|
||||
#include "classfile/sharedPathsMiscInfo.hpp"
|
||||
#endif
|
||||
|
||||
// Entry points in zip.dll for loading zip/jar file entries
|
||||
|
||||
@ -146,7 +144,6 @@ ClassPathEntry* ClassLoader::_app_classpath_entries = NULL;
|
||||
ClassPathEntry* ClassLoader::_last_app_classpath_entry = NULL;
|
||||
ClassPathEntry* ClassLoader::_module_path_entries = NULL;
|
||||
ClassPathEntry* ClassLoader::_last_module_path_entry = NULL;
|
||||
SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL;
|
||||
#endif
|
||||
|
||||
// helper routines
|
||||
@ -168,41 +165,6 @@ static const char* get_jimage_version_string() {
|
||||
return (const char*)version_string;
|
||||
}
|
||||
|
||||
class ClasspathStream : public StackObj {
|
||||
const char* _class_path;
|
||||
int _len;
|
||||
int _start;
|
||||
int _end;
|
||||
|
||||
public:
|
||||
ClasspathStream(const char* class_path) {
|
||||
_class_path = class_path;
|
||||
_len = (int)strlen(class_path);
|
||||
_start = 0;
|
||||
_end = 0;
|
||||
}
|
||||
|
||||
bool has_next() {
|
||||
return _start < _len;
|
||||
}
|
||||
|
||||
const char* get_next() {
|
||||
while (_class_path[_end] != '\0' && _class_path[_end] != os::path_separator()[0]) {
|
||||
_end++;
|
||||
}
|
||||
int path_len = _end - _start;
|
||||
char* path = NEW_RESOURCE_ARRAY(char, path_len + 1);
|
||||
strncpy(path, &_class_path[_start], path_len);
|
||||
path[path_len] = '\0';
|
||||
|
||||
while (_class_path[_end] == os::path_separator()[0]) {
|
||||
_end++;
|
||||
}
|
||||
_start = _end;
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
bool ClassLoader::string_ends_with(const char* str, const char* str_to_find) {
|
||||
size_t str_len = strlen(str);
|
||||
size_t str_to_find_len = strlen(str_to_find);
|
||||
@ -284,13 +246,12 @@ PackageEntry* ClassLoader::get_package_entry(const char* class_name, ClassLoader
|
||||
return pkgEntryTable->lookup_only(pkg_symbol);
|
||||
}
|
||||
|
||||
ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() {
|
||||
char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass);
|
||||
strcpy(copy, dir);
|
||||
_dir = copy;
|
||||
const char* ClassPathEntry::copy_path(const char* path) {
|
||||
char* copy = NEW_C_HEAP_ARRAY(char, strlen(path)+1, mtClass);
|
||||
strcpy(copy, path);
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
|
||||
// construct full path name
|
||||
assert((_dir != NULL) && (name != NULL), "sanity");
|
||||
@ -330,9 +291,7 @@ ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
|
||||
ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name,
|
||||
bool is_boot_append, bool from_class_path_attr) : ClassPathEntry() {
|
||||
_zip = zip;
|
||||
char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass);
|
||||
strcpy(copy, zip_name);
|
||||
_zip_name = copy;
|
||||
_zip_name = copy_path(zip_name);
|
||||
_from_class_path_attr = from_class_path_attr;
|
||||
}
|
||||
|
||||
@ -417,8 +376,7 @@ ClassPathImageEntry::ClassPathImageEntry(JImageFile* jimage, const char* name) :
|
||||
assert(_singleton == NULL, "VM supports only one jimage");
|
||||
DEBUG_ONLY(_singleton = this);
|
||||
size_t len = strlen(name) + 1;
|
||||
_name = NEW_C_HEAP_ARRAY(const char, len, mtClass);
|
||||
strncpy((char *)_name, name, len);
|
||||
_name = copy_path(name);
|
||||
}
|
||||
|
||||
ClassPathImageEntry::~ClassPathImageEntry() {
|
||||
@ -571,30 +529,10 @@ void ClassLoader::setup_bootstrap_search_path() {
|
||||
} else {
|
||||
trace_class_path("bootstrap loader class path=", sys_class_path);
|
||||
}
|
||||
#if INCLUDE_CDS
|
||||
if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
|
||||
_shared_paths_misc_info->add_boot_classpath(sys_class_path);
|
||||
}
|
||||
#endif
|
||||
setup_boot_search_path(sys_class_path);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
int ClassLoader::get_shared_paths_misc_info_size() {
|
||||
return _shared_paths_misc_info->get_used_bytes();
|
||||
}
|
||||
|
||||
void* ClassLoader::get_shared_paths_misc_info() {
|
||||
return _shared_paths_misc_info->buffer();
|
||||
}
|
||||
|
||||
bool ClassLoader::check_shared_paths_misc_info(void *buf, int size, bool is_static) {
|
||||
SharedPathsMiscInfo* checker = new SharedPathsMiscInfo((char*)buf, size);
|
||||
bool result = checker->check(is_static);
|
||||
delete checker;
|
||||
return result;
|
||||
}
|
||||
|
||||
void ClassLoader::setup_app_search_path(const char *class_path) {
|
||||
assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
|
||||
|
||||
@ -977,11 +915,6 @@ bool ClassLoader::update_class_path_entry_list(const char *path,
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
#if INCLUDE_CDS
|
||||
if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
|
||||
_shared_paths_misc_info->add_nonexist_path(path);
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -1601,12 +1534,6 @@ void ClassLoader::initialize() {
|
||||
load_zip_library();
|
||||
// lookup jimage library entry points
|
||||
load_jimage_library();
|
||||
#if INCLUDE_CDS
|
||||
// initialize search path
|
||||
if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
|
||||
_shared_paths_misc_info = new SharedPathsMiscInfo();
|
||||
}
|
||||
#endif
|
||||
setup_bootstrap_search_path();
|
||||
}
|
||||
|
||||
@ -1614,7 +1541,6 @@ void ClassLoader::initialize() {
|
||||
void ClassLoader::initialize_shared_path() {
|
||||
if (DumpSharedSpaces || DynamicDumpSharedSpaces) {
|
||||
ClassLoaderExt::setup_search_paths();
|
||||
_shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -47,17 +47,19 @@ template <typename T> class GrowableArray;
|
||||
class ClassPathEntry : public CHeapObj<mtClass> {
|
||||
private:
|
||||
ClassPathEntry* volatile _next;
|
||||
protected:
|
||||
const char* copy_path(const char*path);
|
||||
public:
|
||||
ClassPathEntry* next() const;
|
||||
virtual ~ClassPathEntry() {}
|
||||
void set_next(ClassPathEntry* next);
|
||||
virtual bool is_modules_image() const = 0;
|
||||
virtual bool is_jar_file() const = 0;
|
||||
virtual bool is_modules_image() const { return false; }
|
||||
virtual bool is_jar_file() const { return false; }
|
||||
// Is this entry created from the "Class-path" attribute from a JAR Manifest?
|
||||
virtual bool from_class_path_attr() const = 0;
|
||||
virtual bool from_class_path_attr() const { return false; }
|
||||
virtual const char* name() const = 0;
|
||||
virtual JImageFile* jimage() const = 0;
|
||||
virtual void close_jimage() = 0;
|
||||
virtual JImageFile* jimage() const { return NULL; }
|
||||
virtual void close_jimage() {}
|
||||
// Constructor
|
||||
ClassPathEntry() : _next(NULL) {}
|
||||
// Attempt to locate file_name through this class path entry.
|
||||
@ -73,18 +75,14 @@ class ClassPathDirEntry: public ClassPathEntry {
|
||||
private:
|
||||
const char* _dir; // Name of directory
|
||||
public:
|
||||
bool is_modules_image() const { return false; }
|
||||
bool is_jar_file() const { return false; }
|
||||
bool from_class_path_attr() const { return false; }
|
||||
const char* name() const { return _dir; }
|
||||
JImageFile* jimage() const { return NULL; }
|
||||
void close_jimage() {}
|
||||
ClassPathDirEntry(const char* dir);
|
||||
ClassPathDirEntry(const char* dir) {
|
||||
_dir = copy_path(dir);
|
||||
}
|
||||
virtual ~ClassPathDirEntry() {}
|
||||
ClassFileStream* open_stream(const char* name, TRAPS);
|
||||
};
|
||||
|
||||
|
||||
// Type definitions for zip file and zip file entry
|
||||
typedef void* jzfile;
|
||||
typedef struct {
|
||||
@ -104,12 +102,9 @@ class ClassPathZipEntry: public ClassPathEntry {
|
||||
const char* _zip_name; // Name of zip archive
|
||||
bool _from_class_path_attr; // From the "Class-path" attribute of a jar file
|
||||
public:
|
||||
bool is_modules_image() const { return false; }
|
||||
bool is_jar_file() const { return true; }
|
||||
bool from_class_path_attr() const { return _from_class_path_attr; }
|
||||
const char* name() const { return _zip_name; }
|
||||
JImageFile* jimage() const { return NULL; }
|
||||
void close_jimage() {}
|
||||
ClassPathZipEntry(jzfile* zip, const char* zip_name, bool is_boot_append, bool from_class_path_attr);
|
||||
virtual ~ClassPathZipEntry();
|
||||
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
|
||||
@ -126,8 +121,6 @@ private:
|
||||
DEBUG_ONLY(static ClassPathImageEntry* _singleton;)
|
||||
public:
|
||||
bool is_modules_image() const;
|
||||
bool is_jar_file() const { return false; }
|
||||
bool from_class_path_attr() const { return false; }
|
||||
bool is_open() const { return _jimage != NULL; }
|
||||
const char* name() const { return _name == NULL ? "" : _name; }
|
||||
JImageFile* jimage() const { return _jimage; }
|
||||
@ -156,8 +149,6 @@ public:
|
||||
void add_to_list(ClassPathEntry* new_entry);
|
||||
};
|
||||
|
||||
class SharedPathsMiscInfo;
|
||||
|
||||
class ClassLoader: AllStatic {
|
||||
public:
|
||||
enum ClassLoaderType {
|
||||
@ -230,8 +221,6 @@ class ClassLoader: AllStatic {
|
||||
static ClassPathEntry* _last_append_entry;
|
||||
|
||||
// Info used by CDS
|
||||
CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;)
|
||||
|
||||
CDS_ONLY(static ClassPathEntry* _app_classpath_entries;)
|
||||
CDS_ONLY(static ClassPathEntry* _last_app_classpath_entry;)
|
||||
CDS_ONLY(static ClassPathEntry* _module_path_entries;)
|
||||
@ -416,10 +405,6 @@ class ClassLoader: AllStatic {
|
||||
}
|
||||
return num_entries;
|
||||
}
|
||||
static void finalize_shared_paths_misc_info();
|
||||
static int get_shared_paths_misc_info_size();
|
||||
static void* get_shared_paths_misc_info();
|
||||
static bool check_shared_paths_misc_info(void* info, int size, bool is_static);
|
||||
static void exit_with_path_failure(const char* error, const char* message);
|
||||
static char* skip_uri_protocol(char* source);
|
||||
static void record_result(InstanceKlass* ik, const ClassFileStream* stream, TRAPS);
|
||||
|
||||
@ -30,7 +30,6 @@
|
||||
#include "classfile/classLoaderData.inline.hpp"
|
||||
#include "classfile/klassFactory.hpp"
|
||||
#include "classfile/modules.hpp"
|
||||
#include "classfile/sharedPathsMiscInfo.hpp"
|
||||
#include "classfile/systemDictionaryShared.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
@ -74,7 +73,6 @@ void ClassLoaderExt::setup_app_search_path() {
|
||||
trace_class_path("app loader class path (skipped)=", app_class_path);
|
||||
} else {
|
||||
trace_class_path("app loader class path=", app_class_path);
|
||||
shared_paths_misc_info()->add_app_classpath(app_class_path);
|
||||
ClassLoader::setup_app_search_path(app_class_path);
|
||||
}
|
||||
}
|
||||
@ -212,8 +210,12 @@ void ClassLoaderExt::process_jar_manifest(ClassPathEntry* entry,
|
||||
char* libname = NEW_RESOURCE_ARRAY(char, libname_len + 1);
|
||||
int n = os::snprintf(libname, libname_len + 1, "%.*s%s", dir_len, dir_name, file_start);
|
||||
assert((size_t)n == libname_len, "Unexpected number of characters in string");
|
||||
trace_class_path("library = ", libname);
|
||||
ClassLoader::update_class_path_entry_list(libname, true, false, true /* from_class_path_attr */);
|
||||
if (ClassLoader::update_class_path_entry_list(libname, true, false, true /* from_class_path_attr */)) {
|
||||
trace_class_path("library = ", libname);
|
||||
} else {
|
||||
trace_class_path("library (non-existent) = ", libname);
|
||||
FileMapInfo::record_non_existent_class_path_entry(libname);
|
||||
}
|
||||
}
|
||||
|
||||
file_start = file_end;
|
||||
@ -222,7 +224,6 @@ void ClassLoaderExt::process_jar_manifest(ClassPathEntry* entry,
|
||||
}
|
||||
|
||||
void ClassLoaderExt::setup_search_paths() {
|
||||
shared_paths_misc_info()->record_app_offset();
|
||||
ClassLoaderExt::setup_app_search_path();
|
||||
}
|
||||
|
||||
@ -248,12 +249,6 @@ void ClassLoaderExt::record_result(const s2 classpath_index,
|
||||
result->set_class_loader_type(classloader_type);
|
||||
}
|
||||
|
||||
void ClassLoaderExt::finalize_shared_paths_misc_info() {
|
||||
if (!_has_app_classes) {
|
||||
shared_paths_misc_info()->pop_app();
|
||||
}
|
||||
}
|
||||
|
||||
// Load the class of the given name from the location given by path. The path is specified by
|
||||
// the "source:" in the class list file (see classListParser.cpp), and can be a directory or
|
||||
// a JAR file.
|
||||
|
||||
@ -47,9 +47,6 @@ private:
|
||||
static char* get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size);
|
||||
static void setup_app_search_path(); // Only when -Xshare:dump
|
||||
static void process_module_table(ModuleEntryTable* met, TRAPS);
|
||||
static SharedPathsMiscInfo* shared_paths_misc_info() {
|
||||
return (SharedPathsMiscInfo*)_shared_paths_misc_info;
|
||||
}
|
||||
// index of first app JAR in shared classpath entry table
|
||||
static jshort _app_class_paths_start_index;
|
||||
// index of first modular JAR in shared modulepath entry table
|
||||
@ -84,8 +81,6 @@ public:
|
||||
return read_manifest(entry, manifest_size, false, THREAD);
|
||||
}
|
||||
|
||||
static void finalize_shared_paths_misc_info();
|
||||
|
||||
static jshort app_class_paths_start_index() { return _app_class_paths_start_index; }
|
||||
|
||||
static jshort app_module_paths_start_index() { return _app_module_paths_start_index; }
|
||||
|
||||
@ -1,178 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/classLoader.hpp"
|
||||
#include "classfile/sharedPathsMiscInfo.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/filemap.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
SharedPathsMiscInfo::SharedPathsMiscInfo() {
|
||||
_app_offset = 0;
|
||||
_buf_size = INITIAL_BUF_SIZE;
|
||||
_cur_ptr = _buf_start = NEW_C_HEAP_ARRAY(char, _buf_size, mtClass);
|
||||
_allocated = true;
|
||||
}
|
||||
|
||||
SharedPathsMiscInfo::~SharedPathsMiscInfo() {
|
||||
if (_allocated) {
|
||||
FREE_C_HEAP_ARRAY(char, _buf_start);
|
||||
}
|
||||
}
|
||||
|
||||
void SharedPathsMiscInfo::add_path(const char* path, int type) {
|
||||
log_info(class, path)("type=%s ", type_name(type));
|
||||
ClassLoader::trace_class_path("add misc shared path ", path);
|
||||
write(path, strlen(path) + 1);
|
||||
write_jint(jint(type));
|
||||
}
|
||||
|
||||
void SharedPathsMiscInfo::ensure_size(size_t needed_bytes) {
|
||||
assert(_allocated, "cannot modify buffer during validation.");
|
||||
int used = get_used_bytes();
|
||||
int target = used + int(needed_bytes);
|
||||
if (target > _buf_size) {
|
||||
_buf_size = _buf_size * 2 + (int)needed_bytes;
|
||||
_buf_start = REALLOC_C_HEAP_ARRAY(char, _buf_start, _buf_size, mtClass);
|
||||
_cur_ptr = _buf_start + used;
|
||||
_end_ptr = _buf_start + _buf_size;
|
||||
}
|
||||
}
|
||||
|
||||
void SharedPathsMiscInfo::write(const void* ptr, size_t size) {
|
||||
ensure_size(size);
|
||||
memcpy(_cur_ptr, ptr, size);
|
||||
_cur_ptr += size;
|
||||
}
|
||||
|
||||
bool SharedPathsMiscInfo::read(void* ptr, size_t size) {
|
||||
if (_cur_ptr + size <= _end_ptr) {
|
||||
memcpy(ptr, _cur_ptr, size);
|
||||
_cur_ptr += size;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SharedPathsMiscInfo::fail(const char* msg, const char* name) {
|
||||
ClassLoader::trace_class_path(msg, name);
|
||||
MetaspaceShared::set_archive_loading_failed();
|
||||
return false;
|
||||
}
|
||||
|
||||
void SharedPathsMiscInfo::print_path(outputStream* out, int type, const char* path) {
|
||||
switch (type) {
|
||||
case BOOT_PATH:
|
||||
out->print("Expecting BOOT path=%s", path);
|
||||
break;
|
||||
case NON_EXIST:
|
||||
out->print("Expecting that %s does not exist", path);
|
||||
break;
|
||||
case APP_PATH:
|
||||
ClassLoader::trace_class_path("Expecting -Djava.class.path=", path);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
bool SharedPathsMiscInfo::check(bool is_static) {
|
||||
// The whole buffer must be 0 terminated so that we can use strlen and strcmp
|
||||
// without fear.
|
||||
_end_ptr -= sizeof(jint);
|
||||
if (_cur_ptr >= _end_ptr) {
|
||||
return fail("Truncated archive file header");
|
||||
}
|
||||
if (*_end_ptr != 0) {
|
||||
return fail("Corrupted archive file header");
|
||||
}
|
||||
|
||||
jshort cur_index = 0;
|
||||
FileMapHeader* header = is_static ? FileMapInfo::current_info()->header() :
|
||||
FileMapInfo::dynamic_info()->header();
|
||||
jshort max_cp_index = header->max_used_path_index();
|
||||
jshort module_paths_start_index = header->app_module_paths_start_index();
|
||||
while (_cur_ptr < _end_ptr) {
|
||||
jint type;
|
||||
const char* path = _cur_ptr;
|
||||
_cur_ptr += strlen(path) + 1;
|
||||
|
||||
if (!read_jint(&type)) {
|
||||
return fail("Corrupted archive file header");
|
||||
}
|
||||
LogTarget(Info, class, path) lt;
|
||||
if (lt.is_enabled()) {
|
||||
lt.print("type=%s ", type_name(type));
|
||||
LogStream ls(lt);
|
||||
print_path(&ls, type, path);
|
||||
ls.cr();
|
||||
}
|
||||
// skip checking the class path(s) which was not referenced during CDS dump
|
||||
if ((cur_index <= max_cp_index) || (cur_index >= module_paths_start_index)) {
|
||||
if (!check(type, path, is_static)) {
|
||||
if (!PrintSharedArchiveAndExit) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ClassLoader::trace_class_path("ok");
|
||||
}
|
||||
} else {
|
||||
ClassLoader::trace_class_path("skipped check");
|
||||
}
|
||||
cur_index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedPathsMiscInfo::check(jint type, const char* path, bool is_static) {
|
||||
assert(UseSharedSpaces, "runtime only");
|
||||
switch (type) {
|
||||
case BOOT_PATH:
|
||||
break;
|
||||
case NON_EXIST:
|
||||
{
|
||||
struct stat st;
|
||||
if (os::stat(path, &st) == 0) {
|
||||
// The file actually exists
|
||||
// But we want it to not exist -> fail
|
||||
return fail("File must not exist");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case APP_PATH:
|
||||
break;
|
||||
default:
|
||||
return fail("Corrupted archive file header");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -1,168 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP
|
||||
#define SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP
|
||||
|
||||
#include "classfile/classLoader.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
|
||||
class outputStream;
|
||||
// During dumping time, when processing class paths, we build up the dump-time
|
||||
// classpath. The JAR files that exist are stored in the list ClassLoader::_first_append_entry.
|
||||
// However, we need to store other "misc" information for run-time checking, such as
|
||||
//
|
||||
// + The values of Arguments::get_sysclasspath() used during dumping.
|
||||
//
|
||||
// + The class path elements specified during dumping but did not exist --
|
||||
// these elements must also be specified at run time, and they also must not
|
||||
// exist at run time.
|
||||
//
|
||||
// These misc items are stored in a linear buffer in SharedPathsMiscInfo.
|
||||
// The storage format is stream oriented to minimize its size.
|
||||
//
|
||||
// When writing the information to the archive file, SharedPathsMiscInfo is stored in
|
||||
// the archive file header. At run-time, this information is used only during initialization
|
||||
// (accessed using read() instead of mmap()), and is deallocated afterwards to save space.
|
||||
//
|
||||
// The SharedPathsMiscInfo class is used for both creating the the information (during
|
||||
// dumping time) and validation (at run time). Different constructors are used in the
|
||||
// two situations. See below.
|
||||
|
||||
class SharedPathsMiscInfo : public CHeapObj<mtClass> {
|
||||
private:
|
||||
int _app_offset;
|
||||
protected:
|
||||
char* _buf_start;
|
||||
char* _cur_ptr;
|
||||
char* _end_ptr;
|
||||
int _buf_size;
|
||||
bool _allocated; // was _buf_start allocated by me?
|
||||
void ensure_size(size_t needed_bytes);
|
||||
void add_path(const char* path, int type);
|
||||
|
||||
void write(const void* ptr, size_t size);
|
||||
bool read(void* ptr, size_t size);
|
||||
|
||||
protected:
|
||||
static bool fail(const char* msg, const char* name = NULL);
|
||||
bool check(jint type, const char* path, bool is_static);
|
||||
|
||||
public:
|
||||
enum {
|
||||
INITIAL_BUF_SIZE = 128
|
||||
};
|
||||
// This constructor is used when creating the misc information (during dump)
|
||||
SharedPathsMiscInfo();
|
||||
// This constructor is used when validating the misc info (during run time)
|
||||
SharedPathsMiscInfo(char *buff, int size) {
|
||||
_app_offset = 0;
|
||||
_cur_ptr = _buf_start = buff;
|
||||
_end_ptr = _buf_start + size;
|
||||
_buf_size = size;
|
||||
_allocated = false;
|
||||
}
|
||||
~SharedPathsMiscInfo();
|
||||
|
||||
int get_used_bytes() {
|
||||
return _cur_ptr - _buf_start;
|
||||
}
|
||||
void* buffer() {
|
||||
return _buf_start;
|
||||
}
|
||||
|
||||
// writing --
|
||||
|
||||
// The path must not exist at run-time
|
||||
void add_nonexist_path(const char* path) {
|
||||
add_path(path, NON_EXIST);
|
||||
}
|
||||
|
||||
// The path must exist, and must contain exactly <num_entries> files/dirs
|
||||
void add_boot_classpath(const char* path) {
|
||||
add_path(path, BOOT_PATH);
|
||||
}
|
||||
|
||||
void add_app_classpath(const char* path) {
|
||||
add_path(path, APP_PATH);
|
||||
}
|
||||
void record_app_offset() {
|
||||
_app_offset = get_used_bytes();
|
||||
}
|
||||
void pop_app() {
|
||||
_cur_ptr = _buf_start + _app_offset;
|
||||
write_jint(0);
|
||||
}
|
||||
|
||||
int write_jint(jint num) {
|
||||
write(&num, sizeof(num));
|
||||
return 0;
|
||||
}
|
||||
void write_time(time_t t) {
|
||||
write(&t, sizeof(t));
|
||||
}
|
||||
void write_long(long l) {
|
||||
write(&l, sizeof(l));
|
||||
}
|
||||
|
||||
bool dump_to_file(int fd) {
|
||||
int n = get_used_bytes();
|
||||
return (os::write(fd, _buf_start, n) == (size_t)n);
|
||||
}
|
||||
|
||||
// reading --
|
||||
|
||||
private:
|
||||
enum {
|
||||
BOOT_PATH = 1,
|
||||
APP_PATH = 2,
|
||||
NON_EXIST = 3
|
||||
};
|
||||
|
||||
const char* type_name(int type) {
|
||||
switch (type) {
|
||||
case BOOT_PATH: return "BOOT";
|
||||
case APP_PATH: return "APP";
|
||||
case NON_EXIST: return "NON_EXIST";
|
||||
default: ShouldNotReachHere(); return "?";
|
||||
}
|
||||
}
|
||||
|
||||
void print_path(outputStream* os, int type, const char* path);
|
||||
|
||||
bool read_jint(jint *ptr) {
|
||||
return read(ptr, sizeof(jint));
|
||||
}
|
||||
bool read_long(long *ptr) {
|
||||
return read(ptr, sizeof(long));
|
||||
}
|
||||
bool read_time(time_t *ptr) {
|
||||
return read(ptr, sizeof(time_t));
|
||||
}
|
||||
|
||||
public:
|
||||
bool check(bool is_static);
|
||||
};
|
||||
|
||||
#endif // SHARE_CLASSFILE_SHAREDPATHSMISCINFO_HPP
|
||||
@ -26,6 +26,7 @@
|
||||
#define SHARE_CODE_VMREG_HPP
|
||||
|
||||
#include "asm/register.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
|
||||
#include "gc/shared/gcUtil.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "gc/epsilon/epsilonMemoryPool.hpp"
|
||||
#include "gc/epsilon/epsilonThreadLocalData.hpp"
|
||||
#include "gc/shared/gcArguments.hpp"
|
||||
#include "gc/shared/locationPrinter.inline.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
@ -305,6 +306,10 @@ void EpsilonHeap::print_on(outputStream *st) const {
|
||||
MetaspaceUtils::print_on(st);
|
||||
}
|
||||
|
||||
bool EpsilonHeap::print_location(outputStream* st, void* addr) const {
|
||||
return BlockLocationPrinter<EpsilonHeap>::print_location(st, addr);
|
||||
}
|
||||
|
||||
void EpsilonHeap::print_tracing_info() const {
|
||||
print_heap_info(used());
|
||||
print_metaspace_info();
|
||||
|
||||
@ -114,8 +114,8 @@ public:
|
||||
virtual void unpin_object(JavaThread* thread, oop obj) { }
|
||||
|
||||
// No support for block parsing.
|
||||
virtual HeapWord* block_start(const void* addr) const { return NULL; }
|
||||
virtual bool block_is_obj(const HeapWord* addr) const { return false; }
|
||||
HeapWord* block_start(const void* addr) const { return NULL; }
|
||||
bool block_is_obj(const HeapWord* addr) const { return false; }
|
||||
|
||||
// No GC threads
|
||||
virtual void print_gc_threads_on(outputStream* st) const {}
|
||||
@ -138,6 +138,7 @@ public:
|
||||
|
||||
virtual void print_on(outputStream* st) const;
|
||||
virtual void print_tracing_info() const;
|
||||
virtual bool print_location(outputStream* st, void* addr) const;
|
||||
|
||||
private:
|
||||
void print_heap_info(size_t used) const;
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1Analytics.hpp"
|
||||
#include "gc/g1/g1Predictions.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/numberSeq.hpp"
|
||||
|
||||
39
src/hotspot/share/gc/g1/g1BufferNodeList.cpp
Normal file
39
src/hotspot/share/gc/g1/g1BufferNodeList.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1BufferNodeList.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
G1BufferNodeList::G1BufferNodeList() :
|
||||
_head(NULL), _tail(NULL), _entry_count(0) {}
|
||||
|
||||
G1BufferNodeList::G1BufferNodeList(BufferNode* head,
|
||||
BufferNode* tail,
|
||||
size_t entry_count) :
|
||||
_head(head), _tail(tail), _entry_count(entry_count)
|
||||
{
|
||||
assert((_head == NULL) == (_tail == NULL), "invariant");
|
||||
assert((_head == NULL) == (_entry_count == 0), "invariant");
|
||||
}
|
||||
42
src/hotspot/share/gc/g1/g1BufferNodeList.hpp
Normal file
42
src/hotspot/share/gc/g1/g1BufferNodeList.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_G1_G1BUFFERNODELIST_HPP
|
||||
#define SHARE_GC_G1_G1BUFFERNODELIST_HPP
|
||||
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class BufferNode;
|
||||
|
||||
struct G1BufferNodeList {
|
||||
BufferNode* _head; // First node in list or NULL if empty.
|
||||
BufferNode* _tail; // Last node in list or NULL if empty.
|
||||
size_t _entry_count; // Sum of entries in nodes in list.
|
||||
|
||||
G1BufferNodeList();
|
||||
G1BufferNodeList(BufferNode* head, BufferNode* tail, size_t entry_count);
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_G1_G1BUFFERNODELIST_HPP
|
||||
|
||||
@ -74,6 +74,7 @@
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/generationSpec.hpp"
|
||||
#include "gc/shared/isGCActiveMark.hpp"
|
||||
#include "gc/shared/locationPrinter.inline.hpp"
|
||||
#include "gc/shared/oopStorageParState.hpp"
|
||||
#include "gc/shared/preservedMarks.inline.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
@ -2490,6 +2491,10 @@ void G1CollectedHeap::print_all_rsets() {
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
bool G1CollectedHeap::print_location(outputStream* st, void* addr) const {
|
||||
return BlockLocationPrinter<G1CollectedHeap>::print_location(st, addr);
|
||||
}
|
||||
|
||||
G1HeapSummary G1CollectedHeap::create_g1_heap_summary() {
|
||||
|
||||
size_t eden_used_bytes = _eden.used_bytes();
|
||||
|
||||
@ -1211,11 +1211,11 @@ public:
|
||||
// address "addr". We say "blocks" instead of "object" since some heaps
|
||||
// may not pack objects densely; a chunk may either be an object or a
|
||||
// non-object.
|
||||
virtual HeapWord* block_start(const void* addr) const;
|
||||
HeapWord* block_start(const void* addr) const;
|
||||
|
||||
// Requires "addr" to be the start of a block, and returns "TRUE" iff
|
||||
// the block is an object.
|
||||
virtual bool block_is_obj(const HeapWord* addr) const;
|
||||
bool block_is_obj(const HeapWord* addr) const;
|
||||
|
||||
// Section on thread-local allocation buffers (TLABs)
|
||||
// See CollectedHeap for semantics.
|
||||
@ -1428,6 +1428,9 @@ public:
|
||||
void print_cset_rsets() PRODUCT_RETURN;
|
||||
void print_all_rsets() PRODUCT_RETURN;
|
||||
|
||||
// Used to print information about locations in the hs_err file.
|
||||
virtual bool print_location(outputStream* st, void* addr) const;
|
||||
|
||||
size_t pending_card_num();
|
||||
};
|
||||
|
||||
|
||||
@ -107,7 +107,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
double G1ConcurrentMarkThread::mmu_sleep_time(G1Policy* g1_policy, bool remark) {
|
||||
double G1ConcurrentMarkThread::mmu_delay_end(G1Policy* g1_policy, bool remark) {
|
||||
// There are 3 reasons to use SuspendibleThreadSetJoiner.
|
||||
// 1. To avoid concurrency problem.
|
||||
// - G1MMUTracker::add_pause(), when_sec() and its variation(when_ms() etc..) can be called
|
||||
@ -119,18 +119,30 @@ double G1ConcurrentMarkThread::mmu_sleep_time(G1Policy* g1_policy, bool remark)
|
||||
SuspendibleThreadSetJoiner sts_join;
|
||||
|
||||
const G1Analytics* analytics = g1_policy->analytics();
|
||||
double now = os::elapsedTime();
|
||||
double prediction_ms = remark ? analytics->predict_remark_time_ms()
|
||||
: analytics->predict_cleanup_time_ms();
|
||||
double prediction = prediction_ms / MILLIUNITS;
|
||||
G1MMUTracker *mmu_tracker = g1_policy->mmu_tracker();
|
||||
return mmu_tracker->when_ms(now, prediction_ms);
|
||||
double now = os::elapsedTime();
|
||||
return now + mmu_tracker->when_sec(now, prediction);
|
||||
}
|
||||
|
||||
void G1ConcurrentMarkThread::delay_to_keep_mmu(G1Policy* g1_policy, bool remark) {
|
||||
if (g1_policy->use_adaptive_young_list_length()) {
|
||||
jlong sleep_time_ms = mmu_sleep_time(g1_policy, remark);
|
||||
if (!_cm->has_aborted() && sleep_time_ms > 0) {
|
||||
os::sleep(this, sleep_time_ms, false);
|
||||
double delay_end_sec = mmu_delay_end(g1_policy, remark);
|
||||
// Wait for timeout or thread termination request.
|
||||
MonitorLocker ml(CGC_lock, Monitor::_no_safepoint_check_flag);
|
||||
while (!_cm->has_aborted()) {
|
||||
double sleep_time_sec = (delay_end_sec - os::elapsedTime());
|
||||
jlong sleep_time_ms = ceil(sleep_time_sec * MILLIUNITS);
|
||||
if (sleep_time_ms <= 0) {
|
||||
break; // Passed end time.
|
||||
} else if (ml.wait(sleep_time_ms, Monitor::_no_safepoint_check_flag)) {
|
||||
break; // Timeout => reached end time.
|
||||
} else if (should_terminate()) {
|
||||
break; // Wakeup for pending termination request.
|
||||
}
|
||||
// Other (possibly spurious) wakeup. Retry with updated sleep time.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ class G1ConcurrentMarkThread: public ConcurrentGCThread {
|
||||
void sleep_before_next_cycle();
|
||||
// Delay marking to meet MMU.
|
||||
void delay_to_keep_mmu(G1Policy* g1_policy, bool remark);
|
||||
double mmu_sleep_time(G1Policy* g1_policy, bool remark);
|
||||
double mmu_delay_end(G1Policy* g1_policy, bool remark);
|
||||
|
||||
void run_service();
|
||||
void stop_service();
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1BufferNodeList.hpp"
|
||||
#include "gc/g1/g1CardTableEntryClosure.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1DirtyCardQueue.hpp"
|
||||
@ -215,7 +216,7 @@ void G1DirtyCardQueueSet::notify_if_necessary() {
|
||||
// must share the monitor.
|
||||
void G1DirtyCardQueueSet::merge_bufferlists(G1RedirtyCardsQueueSet* src) {
|
||||
assert(allocator() == src->allocator(), "precondition");
|
||||
const G1RedirtyCardsBufferList from = src->take_all_completed_buffers();
|
||||
const G1BufferNodeList from = src->take_all_completed_buffers();
|
||||
if (from._head == NULL) return;
|
||||
|
||||
MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag);
|
||||
|
||||
@ -28,20 +28,6 @@
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
// G1RedirtyCardsBufferList
|
||||
|
||||
G1RedirtyCardsBufferList::G1RedirtyCardsBufferList() :
|
||||
_head(NULL), _tail(NULL), _entry_count(0) {}
|
||||
|
||||
G1RedirtyCardsBufferList::G1RedirtyCardsBufferList(BufferNode* head,
|
||||
BufferNode* tail,
|
||||
size_t entry_count) :
|
||||
_head(head), _tail(tail), _entry_count(entry_count)
|
||||
{
|
||||
assert((_head == NULL) == (_tail == NULL), "invariant");
|
||||
assert((_head == NULL) == (_entry_count == 0), "invariant");
|
||||
}
|
||||
|
||||
// G1RedirtyCardsQueueBase::LocalQSet
|
||||
|
||||
G1RedirtyCardsQueueBase::LocalQSet::LocalQSet(G1RedirtyCardsQueueSet* shared_qset) :
|
||||
@ -67,9 +53,9 @@ void G1RedirtyCardsQueueBase::LocalQSet::enqueue_completed_buffer(BufferNode* no
|
||||
}
|
||||
}
|
||||
|
||||
G1RedirtyCardsBufferList G1RedirtyCardsQueueBase::LocalQSet::take_all_completed_buffers() {
|
||||
G1RedirtyCardsBufferList result = _buffers;
|
||||
_buffers = G1RedirtyCardsBufferList();
|
||||
G1BufferNodeList G1RedirtyCardsQueueBase::LocalQSet::take_all_completed_buffers() {
|
||||
G1BufferNodeList result = _buffers;
|
||||
_buffers = G1BufferNodeList();
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -126,9 +112,9 @@ BufferNode* G1RedirtyCardsQueueSet::all_completed_buffers() const {
|
||||
return _list.top();
|
||||
}
|
||||
|
||||
G1RedirtyCardsBufferList G1RedirtyCardsQueueSet::take_all_completed_buffers() {
|
||||
G1BufferNodeList G1RedirtyCardsQueueSet::take_all_completed_buffers() {
|
||||
DEBUG_ONLY(_collecting = false;)
|
||||
G1RedirtyCardsBufferList result(_list.pop_all(), _tail, _entry_count);
|
||||
G1BufferNodeList result(_list.pop_all(), _tail, _entry_count);
|
||||
_tail = NULL;
|
||||
_entry_count = 0;
|
||||
DEBUG_ONLY(_collecting = true;)
|
||||
@ -154,7 +140,7 @@ void G1RedirtyCardsQueueSet::enqueue_completed_buffer(BufferNode* node) {
|
||||
|
||||
void G1RedirtyCardsQueueSet::merge_bufferlist(LocalQSet* src) {
|
||||
assert(_collecting, "precondition");
|
||||
const G1RedirtyCardsBufferList from = src->take_all_completed_buffers();
|
||||
const G1BufferNodeList from = src->take_all_completed_buffers();
|
||||
if (from._head != NULL) {
|
||||
assert(from._tail != NULL, "invariant");
|
||||
Atomic::add(from._entry_count, &_entry_count);
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#ifndef SHARE_GC_G1_G1REDIRTYCARDSQUEUE_HPP
|
||||
#define SHARE_GC_G1_G1REDIRTYCARDSQUEUE_HPP
|
||||
|
||||
#include "gc/g1/g1BufferNodeList.hpp"
|
||||
#include "gc/shared/ptrQueue.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/padded.hpp"
|
||||
@ -33,15 +34,6 @@ class G1CardTableEntryClosure;
|
||||
class G1RedirtyCardsQueue;
|
||||
class G1RedirtyCardsQueueSet;
|
||||
|
||||
struct G1RedirtyCardsBufferList {
|
||||
BufferNode* _head;
|
||||
BufferNode* _tail;
|
||||
size_t _entry_count;
|
||||
|
||||
G1RedirtyCardsBufferList();
|
||||
G1RedirtyCardsBufferList(BufferNode* head, BufferNode* tail, size_t entry_count);
|
||||
};
|
||||
|
||||
// Provide G1RedirtyCardsQueue with a thread-local qset. It provides an
|
||||
// uncontended staging area for completed buffers, to be flushed to the
|
||||
// shared qset en masse. Using the "base from member" idiom so the local
|
||||
@ -52,7 +44,7 @@ class G1RedirtyCardsQueueBase {
|
||||
|
||||
class LocalQSet : public PtrQueueSet {
|
||||
G1RedirtyCardsQueueSet* _shared_qset;
|
||||
G1RedirtyCardsBufferList _buffers;
|
||||
G1BufferNodeList _buffers;
|
||||
|
||||
public:
|
||||
LocalQSet(G1RedirtyCardsQueueSet* shared_qset);
|
||||
@ -64,7 +56,7 @@ class G1RedirtyCardsQueueBase {
|
||||
// Transfer all completed buffers to the shared qset.
|
||||
void flush();
|
||||
|
||||
G1RedirtyCardsBufferList take_all_completed_buffers();
|
||||
G1BufferNodeList take_all_completed_buffers();
|
||||
};
|
||||
|
||||
G1RedirtyCardsQueueBase(G1RedirtyCardsQueueSet* shared_qset) :
|
||||
@ -123,7 +115,7 @@ public:
|
||||
// Processing phase operations.
|
||||
// precondition: Must not be concurrent with buffer collection.
|
||||
BufferNode* all_completed_buffers() const;
|
||||
G1RedirtyCardsBufferList take_all_completed_buffers();
|
||||
G1BufferNodeList take_all_completed_buffers();
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_G1_G1REDIRTYCARDSQUEUE_HPP
|
||||
|
||||
@ -245,9 +245,6 @@
|
||||
"The target number of mixed GCs after a marking cycle.") \
|
||||
range(0, max_uintx) \
|
||||
\
|
||||
experimental(bool, G1PretouchAuxiliaryMemory, false, \
|
||||
"Pre-touch large auxiliary data structures used by the GC.") \
|
||||
\
|
||||
experimental(bool, G1EagerReclaimHumongousObjects, true, \
|
||||
"Try to reclaim dead large objects at every young GC.") \
|
||||
\
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include "gc/shared/gcLocker.hpp"
|
||||
#include "gc/shared/gcWhen.hpp"
|
||||
#include "gc/shared/genArguments.hpp"
|
||||
#include "gc/shared/locationPrinter.inline.hpp"
|
||||
#include "gc/shared/scavengableNMethods.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/metaspaceCounters.hpp"
|
||||
@ -584,6 +585,10 @@ PSHeapSummary ParallelScavengeHeap::create_ps_heap_summary() {
|
||||
return PSHeapSummary(heap_summary, used(), old_summary, old_space, young_summary, eden_space, from_space, to_space);
|
||||
}
|
||||
|
||||
bool ParallelScavengeHeap::print_location(outputStream* st, void* addr) const {
|
||||
return BlockLocationPrinter<ParallelScavengeHeap>::print_location(st, addr);
|
||||
}
|
||||
|
||||
void ParallelScavengeHeap::print_on(outputStream* st) const {
|
||||
young_gen()->print_on(st);
|
||||
old_gen()->print_on(st);
|
||||
|
||||
@ -228,6 +228,9 @@ class ParallelScavengeHeap : public CollectedHeap {
|
||||
PreGenGCValues get_pre_gc_values() const;
|
||||
void print_heap_change(const PreGenGCValues& pre_gc_values) const;
|
||||
|
||||
// Used to print information about locations in the hs_err file.
|
||||
virtual bool print_location(outputStream* st, void* addr) const;
|
||||
|
||||
void verify(VerifyOption option /* ignored */);
|
||||
|
||||
// Resize the young generation. The reserved space for the
|
||||
|
||||
@ -402,28 +402,6 @@ class CollectedHeap : public CHeapObj<mtInternal> {
|
||||
// over live objects.
|
||||
virtual void safe_object_iterate(ObjectClosure* cl) = 0;
|
||||
|
||||
// NOTE! There is no requirement that a collector implement these
|
||||
// functions.
|
||||
//
|
||||
// A CollectedHeap is divided into a dense sequence of "blocks"; that is,
|
||||
// each address in the (reserved) heap is a member of exactly
|
||||
// one block. The defining characteristic of a block is that it is
|
||||
// possible to find its size, and thus to progress forward to the next
|
||||
// block. (Blocks may be of different sizes.) Thus, blocks may
|
||||
// represent Java objects, or they might be free blocks in a
|
||||
// free-list-based heap (or subheap), as long as the two kinds are
|
||||
// distinguishable and the size of each is determinable.
|
||||
|
||||
// Returns the address of the start of the "block" that contains the
|
||||
// address "addr". We say "blocks" instead of "object" since some heaps
|
||||
// may not pack objects densely; a chunk may either be an object or a
|
||||
// non-object.
|
||||
virtual HeapWord* block_start(const void* addr) const = 0;
|
||||
|
||||
// Requires "addr" to be the start of a block, and returns "TRUE" iff
|
||||
// the block is an object.
|
||||
virtual bool block_is_obj(const HeapWord* addr) const = 0;
|
||||
|
||||
// Returns the longest time (in ms) that has elapsed since the last
|
||||
// time that any part of the heap was examined by a garbage collection.
|
||||
virtual jlong millis_since_last_gc() = 0;
|
||||
@ -461,6 +439,9 @@ class CollectedHeap : public CHeapObj<mtInternal> {
|
||||
|
||||
virtual void print_on_error(outputStream* st) const;
|
||||
|
||||
// Used to print information about locations in the hs_err file.
|
||||
virtual bool print_location(outputStream* st, void* addr) const = 0;
|
||||
|
||||
// Print all GC threads (other than the VM thread)
|
||||
// used by this heap.
|
||||
virtual void print_gc_threads_on(outputStream* st) const = 0;
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "gc/shared/gcCause.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
|
||||
class SoftRefPolicy;
|
||||
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
#include "gc/shared/genCollectedHeap.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "gc/shared/generationSpec.hpp"
|
||||
#include "gc/shared/locationPrinter.inline.hpp"
|
||||
#include "gc/shared/oopStorageParState.inline.hpp"
|
||||
#include "gc/shared/scavengableNMethods.hpp"
|
||||
#include "gc/shared/space.hpp"
|
||||
@ -1260,6 +1261,10 @@ void GenCollectedHeap::gc_threads_do(ThreadClosure* tc) const {
|
||||
void GenCollectedHeap::print_gc_threads_on(outputStream* st) const {
|
||||
}
|
||||
|
||||
bool GenCollectedHeap::print_location(outputStream* st, void* addr) const {
|
||||
return BlockLocationPrinter<GenCollectedHeap>::print_location(st, addr);
|
||||
}
|
||||
|
||||
void GenCollectedHeap::print_tracing_info() const {
|
||||
if (log_is_enabled(Debug, gc, heap, exit)) {
|
||||
LogStreamHandle(Debug, gc, heap, exit) lsh;
|
||||
|
||||
@ -260,13 +260,13 @@ public:
|
||||
// address "addr". We say "blocks" instead of "object" since some heaps
|
||||
// may not pack objects densely; a chunk may either be an object or a
|
||||
// non-object.
|
||||
virtual HeapWord* block_start(const void* addr) const;
|
||||
HeapWord* block_start(const void* addr) const;
|
||||
|
||||
// Requires "addr" to be the start of a block, and returns "TRUE" iff
|
||||
// the block is an object. Assumes (and verifies in non-product
|
||||
// builds) that addr is in the allocated part of the heap and is
|
||||
// the start of a chunk.
|
||||
virtual bool block_is_obj(const HeapWord* addr) const;
|
||||
bool block_is_obj(const HeapWord* addr) const;
|
||||
|
||||
// Section on TLAB's.
|
||||
virtual bool supports_tlab_allocation() const;
|
||||
@ -332,6 +332,9 @@ public:
|
||||
virtual void gc_threads_do(ThreadClosure* tc) const;
|
||||
virtual void print_tracing_info() const;
|
||||
|
||||
// Used to print information about locations in the hs_err file.
|
||||
virtual bool print_location(outputStream* st, void* addr) const;
|
||||
|
||||
void print_heap_change(size_t young_prev_used, size_t old_prev_used) const;
|
||||
|
||||
// The functions below are helper functions that a subclass of
|
||||
|
||||
50
src/hotspot/share/gc/shared/locationPrinter.cpp
Normal file
50
src/hotspot/share/gc/shared/locationPrinter.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/locationPrinter.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "oops/klass.hpp"
|
||||
|
||||
bool LocationPrinter::is_valid_obj(void* obj) {
|
||||
if (!is_object_aligned(obj)) {
|
||||
return false;
|
||||
}
|
||||
if (obj < (void*)os::min_page_size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need at least the mark and the klass word in the committed region.
|
||||
if (!os::is_readable_range(obj, (HeapWord*)obj + oopDesc::header_size())) {
|
||||
return false;
|
||||
}
|
||||
if (!Universe::heap()->is_in(obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Klass* k = (Klass*)oopDesc::load_klass_raw((oopDesc*)obj);
|
||||
return Klass::is_valid(k);
|
||||
}
|
||||
48
src/hotspot/share/gc/shared/locationPrinter.hpp
Normal file
48
src/hotspot/share/gc/shared/locationPrinter.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_SHARED_LOCATIONPRINTER_HPP
|
||||
#define SHARE_GC_SHARED_LOCATIONPRINTER_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "oops/oopsHierarchy.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class outputStream;
|
||||
|
||||
class LocationPrinter : AllStatic {
|
||||
public:
|
||||
static bool is_valid_obj(void* addr);
|
||||
};
|
||||
|
||||
template <typename CollectedHeapT>
|
||||
class BlockLocationPrinter : public LocationPrinter {
|
||||
static oop base_oop_or_null(void* addr);
|
||||
|
||||
public:
|
||||
static bool print_location(outputStream* st, void* addr);
|
||||
};
|
||||
|
||||
|
||||
#endif // SHARE_GC_SHARED_LOCATIONPRINTER_HPP
|
||||
87
src/hotspot/share/gc/shared/locationPrinter.inline.hpp
Normal file
87
src/hotspot/share/gc/shared/locationPrinter.inline.hpp
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_GC_SHARED_LOCATIONPRINTER_INLINE_HPP
|
||||
#define SHARE_GC_SHARED_LOCATIONPRINTER_INLINE_HPP
|
||||
|
||||
#include "gc/shared/locationPrinter.hpp"
|
||||
#include "oops/compressedOops.inline.hpp"
|
||||
#include "oops/oopsHierarchy.hpp"
|
||||
|
||||
template <typename CollectedHeapT>
|
||||
oop BlockLocationPrinter<CollectedHeapT>::base_oop_or_null(void* addr) {
|
||||
if (is_valid_obj(addr)) {
|
||||
// We were just given an oop directly.
|
||||
return oop(addr);
|
||||
}
|
||||
|
||||
// Try to find addr using block_start.
|
||||
HeapWord* p = CollectedHeapT::heap()->block_start(addr);
|
||||
if (p != NULL && CollectedHeapT::heap()->block_is_obj(p)) {
|
||||
if (!is_valid_obj(p)) {
|
||||
return NULL;
|
||||
}
|
||||
return oop(p);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename CollectedHeapT>
|
||||
bool BlockLocationPrinter<CollectedHeapT>::print_location(outputStream* st, void* addr) {
|
||||
// Check if addr points into Java heap.
|
||||
if (CollectedHeapT::heap()->is_in(addr)) {
|
||||
oop o = base_oop_or_null(addr);
|
||||
if (o != NULL) {
|
||||
if ((void*)o == addr) {
|
||||
st->print(INTPTR_FORMAT " is an oop: ", p2i(addr));
|
||||
} else {
|
||||
st->print(INTPTR_FORMAT " is pointing into object: " , p2i(addr));
|
||||
}
|
||||
o->print_on(st);
|
||||
return true;
|
||||
}
|
||||
} else if (CollectedHeapT::heap()->is_in_reserved(addr)) {
|
||||
st->print_cr(INTPTR_FORMAT " is an unallocated location in the heap", p2i(addr));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compressed oop needs to be decoded first.
|
||||
#ifdef _LP64
|
||||
if (UseCompressedOops && ((uintptr_t)addr &~ (uintptr_t)max_juint) == 0) {
|
||||
narrowOop narrow_oop = (narrowOop)(uintptr_t)addr;
|
||||
oop o = CompressedOops::decode_raw(narrow_oop);
|
||||
|
||||
if (is_valid_obj((address)o)) {
|
||||
st->print(UINT32_FORMAT " is a compressed pointer to object: ", narrow_oop);
|
||||
o->print_on(st);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // SHARE_GC_SHARED_LOCATIONPRINTER_INLINE_HPP
|
||||
@ -116,10 +116,10 @@ void WeakProcessor::Task::initialize() {
|
||||
StorageState* cur_state = _storage_states;
|
||||
OopStorageSet::Iterator it = OopStorageSet::weak_iterator();
|
||||
for ( ; !it.is_end(); ++it, ++cur_state) {
|
||||
assert((cur_state - _storage_states) < storage_count, "invariant");
|
||||
assert(pointer_delta(cur_state, _storage_states, sizeof(StorageState)) < storage_count, "invariant");
|
||||
new (cur_state) StorageState(*it, _nworkers);
|
||||
}
|
||||
assert((cur_state - _storage_states) == storage_count, "invariant");
|
||||
assert(pointer_delta(cur_state, _storage_states, sizeof(StorageState)) == storage_count, "invariant");
|
||||
StringTable::reset_dead_counter();
|
||||
ResolvedMethodTable::reset_dead_counter();
|
||||
}
|
||||
|
||||
@ -363,7 +363,7 @@ void ShenandoahAsserts::assert_rp_isalive_installed(const char *file, int line)
|
||||
}
|
||||
}
|
||||
|
||||
void ShenandoahAsserts::assert_locked_or_shenandoah_safepoint(const Mutex* lock, const char* file, int line) {
|
||||
void ShenandoahAsserts::assert_locked_or_shenandoah_safepoint(Mutex* lock, const char* file, int line) {
|
||||
if (ShenandoahSafepoint::is_at_shenandoah_safepoint()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ public:
|
||||
static void assert_rp_isalive_not_installed(const char *file, int line);
|
||||
static void assert_rp_isalive_installed(const char *file, int line);
|
||||
|
||||
static void assert_locked_or_shenandoah_safepoint(const Mutex* lock, const char*file, int line);
|
||||
static void assert_locked_or_shenandoah_safepoint(Mutex* lock, const char* file, int line);
|
||||
|
||||
#ifdef ASSERT
|
||||
#define shenandoah_assert_in_heap(interior_loc, obj) \
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "gc/shared/gcArguments.hpp"
|
||||
#include "gc/shared/gcTimer.hpp"
|
||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||
#include "gc/shared/locationPrinter.inline.hpp"
|
||||
#include "gc/shared/memAllocator.hpp"
|
||||
#include "gc/shared/plab.hpp"
|
||||
|
||||
@ -1133,6 +1134,10 @@ bool ShenandoahHeap::block_is_obj(const HeapWord* addr) const {
|
||||
return sp->block_is_obj(addr);
|
||||
}
|
||||
|
||||
bool ShenandoahHeap::print_location(outputStream* st, void* addr) const {
|
||||
return BlockLocationPrinter<ShenandoahHeap>::print_location(st, addr);
|
||||
}
|
||||
|
||||
jlong ShenandoahHeap::millis_since_last_gc() {
|
||||
double v = heuristics()->time_since_last_gc() * 1000;
|
||||
assert(0 <= v && v <= max_jlong, "value should fit: %f", v);
|
||||
|
||||
@ -536,6 +536,7 @@ public:
|
||||
// Used for parsing heap during error printing
|
||||
HeapWord* block_start(const void* addr) const;
|
||||
bool block_is_obj(const HeapWord* addr) const;
|
||||
bool print_location(outputStream* st, void* addr) const;
|
||||
|
||||
// Used for native heap walkers: heap dumpers, mostly
|
||||
void object_iterate(ObjectClosure* cl);
|
||||
|
||||
@ -1217,7 +1217,7 @@ static void call_catch_cleanup_one(PhaseIdealLoop* phase, LoadNode* load, Node*
|
||||
}
|
||||
|
||||
// Sort out the loads that are between a call ant its catch blocks
|
||||
static void process_catch_cleanup_candidate(PhaseIdealLoop* phase, LoadNode* load) {
|
||||
static void process_catch_cleanup_candidate(PhaseIdealLoop* phase, LoadNode* load, bool verify) {
|
||||
bool trace = phase->C->directive()->ZTraceLoadBarriersOption;
|
||||
|
||||
Node* ctrl = get_ctrl_normalized(phase, load);
|
||||
@ -1228,6 +1228,7 @@ static void process_catch_cleanup_candidate(PhaseIdealLoop* phase, LoadNode* loa
|
||||
Node* catch_node = ctrl->isa_Proj()->raw_out(0);
|
||||
if (catch_node->is_Catch()) {
|
||||
if (catch_node->outcnt() > 1) {
|
||||
assert(!verify, "All loads should already have been moved");
|
||||
call_catch_cleanup_one(phase, load, ctrl);
|
||||
} else {
|
||||
if (trace) tty->print_cr("Call catch cleanup with only one catch: load %i ", load->_idx);
|
||||
@ -1245,6 +1246,7 @@ bool ZBarrierSetC2::optimize_loops(PhaseIdealLoop* phase, LoopOptsMode mode, Vec
|
||||
if (mode == LoopOptsZBarrierInsertion) {
|
||||
// First make sure all loads between call and catch are moved to the catch block
|
||||
clean_catch_blocks(phase);
|
||||
DEBUG_ONLY(clean_catch_blocks(phase, true /* verify */);)
|
||||
|
||||
// Then expand barriers on all loads
|
||||
insert_load_barriers(phase);
|
||||
@ -1398,7 +1400,7 @@ void ZBarrierSetC2::insert_barriers_on_unsafe(PhaseIdealLoop* phase) const {
|
||||
// Sometimes the loads use will be at a place dominated by all catch blocks, then we need
|
||||
// a load in each catch block, and a Phi at the dominated use.
|
||||
|
||||
void ZBarrierSetC2::clean_catch_blocks(PhaseIdealLoop* phase) const {
|
||||
void ZBarrierSetC2::clean_catch_blocks(PhaseIdealLoop* phase, bool verify) const {
|
||||
|
||||
Compile *C = phase->C;
|
||||
uint new_ids = C->unique();
|
||||
@ -1425,7 +1427,7 @@ void ZBarrierSetC2::clean_catch_blocks(PhaseIdealLoop* phase) const {
|
||||
LoadNode* load = n->isa_Load();
|
||||
// only care about loads that will have a barrier
|
||||
if (load_require_barrier(load)) {
|
||||
process_catch_cleanup_candidate(phase, load);
|
||||
process_catch_cleanup_candidate(phase, load, verify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,7 +207,7 @@ public:
|
||||
private:
|
||||
// Load barrier insertion and expansion internal
|
||||
void insert_barriers_on_unsafe(PhaseIdealLoop* phase) const;
|
||||
void clean_catch_blocks(PhaseIdealLoop* phase) const;
|
||||
void clean_catch_blocks(PhaseIdealLoop* phase, bool verify = false) const;
|
||||
void insert_load_barriers(PhaseIdealLoop* phase) const;
|
||||
LoadNode* insert_one_loadbarrier(PhaseIdealLoop* phase, LoadNode* load, Node* ctrl) const;
|
||||
void insert_one_loadbarrier_inner(PhaseIdealLoop* phase, LoadNode* load, Node* ctrl, VectorSet visited) const;
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/gcHeapSummary.hpp"
|
||||
#include "gc/shared/locationPrinter.hpp"
|
||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||
#include "gc/z/zCollectedHeap.hpp"
|
||||
#include "gc/z/zGlobals.hpp"
|
||||
@ -249,14 +250,6 @@ void ZCollectedHeap::safe_object_iterate(ObjectClosure* cl) {
|
||||
_heap.object_iterate(cl, true /* visit_weaks */);
|
||||
}
|
||||
|
||||
HeapWord* ZCollectedHeap::block_start(const void* addr) const {
|
||||
return (HeapWord*)_heap.block_start((uintptr_t)addr);
|
||||
}
|
||||
|
||||
bool ZCollectedHeap::block_is_obj(const HeapWord* addr) const {
|
||||
return _heap.block_is_obj((uintptr_t)addr);
|
||||
}
|
||||
|
||||
void ZCollectedHeap::register_nmethod(nmethod* nm) {
|
||||
ZNMethod::register_nmethod(nm);
|
||||
}
|
||||
@ -356,6 +349,16 @@ void ZCollectedHeap::print_tracing_info() const {
|
||||
// Does nothing
|
||||
}
|
||||
|
||||
bool ZCollectedHeap::print_location(outputStream* st, void* addr) const {
|
||||
if (LocationPrinter::is_valid_obj(addr)) {
|
||||
st->print(INTPTR_FORMAT " is a %s oop: ", p2i(addr),
|
||||
ZAddress::is_good(reinterpret_cast<uintptr_t>(addr)) ? "good" : "bad");
|
||||
cast_to_oop(addr)->print_on(st);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ZCollectedHeap::verify(VerifyOption option /* ignored */) {
|
||||
_heap.verify();
|
||||
}
|
||||
|
||||
@ -100,9 +100,6 @@ public:
|
||||
virtual void object_iterate(ObjectClosure* cl);
|
||||
virtual void safe_object_iterate(ObjectClosure* cl);
|
||||
|
||||
virtual HeapWord* block_start(const void* addr) const;
|
||||
virtual bool block_is_obj(const HeapWord* addr) const;
|
||||
|
||||
virtual void register_nmethod(nmethod* nm);
|
||||
virtual void unregister_nmethod(nmethod* nm);
|
||||
virtual void flush_nmethod(nmethod* nm);
|
||||
@ -124,6 +121,7 @@ public:
|
||||
virtual void print_extended_on(outputStream* st) const;
|
||||
virtual void print_gc_threads_on(outputStream* st) const;
|
||||
virtual void print_tracing_info() const;
|
||||
virtual bool print_location(outputStream* st, void* addr) const;
|
||||
|
||||
virtual void prepare_for_verify();
|
||||
virtual void verify(VerifyOption option /* ignored */);
|
||||
|
||||
@ -64,7 +64,7 @@ ZHeap* ZHeap::_heap = NULL;
|
||||
|
||||
ZHeap::ZHeap() :
|
||||
_workers(),
|
||||
_object_allocator(_workers.nworkers()),
|
||||
_object_allocator(),
|
||||
_page_allocator(heap_min_size(), heap_initial_size(), heap_max_size(), heap_max_reserve_size()),
|
||||
_page_table(),
|
||||
_forwarding_table(),
|
||||
@ -194,16 +194,6 @@ bool ZHeap::is_in(uintptr_t addr) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t ZHeap::block_start(uintptr_t addr) const {
|
||||
const ZPage* const page = _page_table.get(addr);
|
||||
return page->block_start(addr);
|
||||
}
|
||||
|
||||
bool ZHeap::block_is_obj(uintptr_t addr) const {
|
||||
const ZPage* const page = _page_table.get(addr);
|
||||
return page->block_is_obj(addr);
|
||||
}
|
||||
|
||||
uint ZHeap::nconcurrent_worker_threads() const {
|
||||
return _workers.nconcurrent();
|
||||
}
|
||||
|
||||
@ -107,10 +107,6 @@ public:
|
||||
bool is_in(uintptr_t addr) const;
|
||||
uint32_t hash_oop(oop obj) const;
|
||||
|
||||
// Block
|
||||
uintptr_t block_start(uintptr_t addr) const;
|
||||
bool block_is_obj(uintptr_t addr) const;
|
||||
|
||||
// Workers
|
||||
uint nconcurrent_worker_threads() const;
|
||||
uint nconcurrent_no_boost_worker_threads() const;
|
||||
|
||||
@ -41,8 +41,7 @@
|
||||
static const ZStatCounter ZCounterUndoObjectAllocationSucceeded("Memory", "Undo Object Allocation Succeeded", ZStatUnitOpsPerSecond);
|
||||
static const ZStatCounter ZCounterUndoObjectAllocationFailed("Memory", "Undo Object Allocation Failed", ZStatUnitOpsPerSecond);
|
||||
|
||||
ZObjectAllocator::ZObjectAllocator(uint nworkers) :
|
||||
_nworkers(nworkers),
|
||||
ZObjectAllocator::ZObjectAllocator() :
|
||||
_used(0),
|
||||
_undone(0),
|
||||
_shared_medium_page(NULL),
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
|
||||
class ZObjectAllocator {
|
||||
private:
|
||||
const uint _nworkers;
|
||||
ZPerCPU<size_t> _used;
|
||||
ZPerCPU<size_t> _undone;
|
||||
ZContended<ZPage*> _shared_medium_page;
|
||||
@ -64,7 +63,7 @@ private:
|
||||
bool undo_alloc_object(ZPage* page, uintptr_t addr, size_t size);
|
||||
|
||||
public:
|
||||
ZObjectAllocator(uint nworkers);
|
||||
ZObjectAllocator();
|
||||
|
||||
uintptr_t alloc_object(size_t size);
|
||||
|
||||
|
||||
@ -90,9 +90,6 @@ public:
|
||||
|
||||
bool is_in(uintptr_t addr) const;
|
||||
|
||||
uintptr_t block_start(uintptr_t addr) const;
|
||||
bool block_is_obj(uintptr_t addr) const;
|
||||
|
||||
bool is_marked() const;
|
||||
bool is_object_live(uintptr_t addr) const;
|
||||
bool is_object_strongly_live(uintptr_t addr) const;
|
||||
|
||||
@ -177,18 +177,6 @@ inline bool ZPage::is_in(uintptr_t addr) const {
|
||||
return offset >= start() && offset < top();
|
||||
}
|
||||
|
||||
inline uintptr_t ZPage::block_start(uintptr_t addr) const {
|
||||
if (block_is_obj(addr)) {
|
||||
return addr;
|
||||
} else {
|
||||
return ZAddress::good(top());
|
||||
}
|
||||
}
|
||||
|
||||
inline bool ZPage::block_is_obj(uintptr_t addr) const {
|
||||
return ZAddress::offset(addr) < top();
|
||||
}
|
||||
|
||||
inline bool ZPage::is_marked() const {
|
||||
assert(is_relocatable(), "Invalid page state");
|
||||
return _livemap.is_marked();
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
#define SHARE_GC_Z_ZPHYSICALMEMORY_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include OS_CPU_HEADER(gc/z/zPhysicalMemoryBacking)
|
||||
#include OS_HEADER(gc/z/zPhysicalMemoryBacking)
|
||||
|
||||
class ZPhysicalMemorySegment : public CHeapObj<mtGC> {
|
||||
private:
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
#include "gc/z/zNUMA.hpp"
|
||||
#include "gc/z/zThread.hpp"
|
||||
#include "gc/z/zUtils.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
|
||||
template <typename S>
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#define NUM_CDS_REGIONS 8 // this must be the same as MetaspaceShared::n_regions
|
||||
#define CDS_ARCHIVE_MAGIC 0xf00baba2
|
||||
#define CDS_DYNAMIC_ARCHIVE_MAGIC 0xf00baba8
|
||||
#define CURRENT_CDS_ARCHIVE_VERSION 6
|
||||
#define CURRENT_CDS_ARCHIVE_VERSION 7
|
||||
#define INVALID_CDS_ARCHIVE_VERSION -1
|
||||
|
||||
struct CDSFileMapRegion {
|
||||
|
||||
@ -771,12 +771,7 @@ JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, Ba
|
||||
Handle h_obj(thread, elem->obj());
|
||||
assert(Universe::heap()->is_in_reserved_or_null(h_obj()),
|
||||
"must be NULL or an object");
|
||||
if (UseBiasedLocking) {
|
||||
// Retry fast entry if bias is revoked to avoid unnecessary inflation
|
||||
ObjectSynchronizer::fast_enter(h_obj, elem->lock(), true, CHECK);
|
||||
} else {
|
||||
ObjectSynchronizer::slow_enter(h_obj, elem->lock(), CHECK);
|
||||
}
|
||||
ObjectSynchronizer::enter(h_obj, elem->lock(), CHECK);
|
||||
assert(Universe::heap()->is_in_reserved_or_null(elem->obj()),
|
||||
"must be NULL or an object");
|
||||
#ifdef ASSERT
|
||||
@ -796,7 +791,7 @@ JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorexit(JavaThread* thread, Bas
|
||||
if (elem == NULL || h_obj()->is_unlocked()) {
|
||||
THROW(vmSymbols::java_lang_IllegalMonitorStateException());
|
||||
}
|
||||
ObjectSynchronizer::slow_exit(h_obj(), elem->lock(), thread);
|
||||
ObjectSynchronizer::exit(h_obj(), elem->lock(), thread);
|
||||
// Free entry. This must be done here, since a pending exception might be installed on
|
||||
// exit. If it is not cleared, the exception handling code will try to unlock the monitor again.
|
||||
elem->set_obj(NULL);
|
||||
|
||||
@ -205,7 +205,7 @@ C2V_VMENTRY_NULL(jobject, getFlagValue, (JNIEnv* env, jobject c2vm, jobject name
|
||||
JVMCI_THROW_NULL(NullPointerException);
|
||||
}
|
||||
const char* cstring = JVMCIENV->as_utf8_string(name);
|
||||
JVMFlag* flag = JVMFlag::find_flag(cstring, strlen(cstring), /* allow_locked */ true, /* return_flag */ true);
|
||||
const JVMFlag* flag = JVMFlag::find_declared_flag(cstring);
|
||||
if (flag == NULL) {
|
||||
return c2vm;
|
||||
}
|
||||
|
||||
@ -369,7 +369,7 @@ jobjectArray readConfiguration0(JNIEnv *env, JVMCI_TRAPS) {
|
||||
#define COUNT_FLAG(ignore) +1
|
||||
#ifdef ASSERT
|
||||
#define CHECK_FLAG(type, name) { \
|
||||
JVMFlag* flag = JVMFlag::find_flag(#name, strlen(#name), /*allow_locked*/ true, /* return_flag */ true); \
|
||||
const JVMFlag* flag = JVMFlag::find_declared_flag(#name); \
|
||||
assert(flag != NULL, "No such flag named " #name); \
|
||||
assert(flag->is_##type(), "JVMFlag " #name " is not of type " #type); \
|
||||
}
|
||||
|
||||
@ -394,17 +394,7 @@ JRT_ENTRY_NO_ASYNC(void, JVMCIRuntime::monitorenter(JavaThread* thread, oopDesc*
|
||||
}
|
||||
Handle h_obj(thread, obj);
|
||||
assert(oopDesc::is_oop(h_obj()), "must be NULL or an object");
|
||||
if (UseBiasedLocking) {
|
||||
// Retry fast entry if bias is revoked to avoid unnecessary inflation
|
||||
ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK);
|
||||
} else {
|
||||
if (JVMCIUseFastLocking) {
|
||||
// When using fast locking, the compiled code has already tried the fast case
|
||||
ObjectSynchronizer::slow_enter(h_obj, lock, THREAD);
|
||||
} else {
|
||||
ObjectSynchronizer::fast_enter(h_obj, lock, false, THREAD);
|
||||
}
|
||||
}
|
||||
ObjectSynchronizer::enter(h_obj, lock, THREAD);
|
||||
TRACE_jvmci_3("%s: exiting locking slow with obj=" INTPTR_FORMAT, thread->name(), p2i(obj));
|
||||
JRT_END
|
||||
|
||||
@ -426,12 +416,7 @@ JRT_LEAF(void, JVMCIRuntime::monitorexit(JavaThread* thread, oopDesc* obj, Basic
|
||||
}
|
||||
#endif
|
||||
|
||||
if (JVMCIUseFastLocking) {
|
||||
// When using fast locking, the compiled code has already tried the fast case
|
||||
ObjectSynchronizer::slow_exit(obj, lock, THREAD);
|
||||
} else {
|
||||
ObjectSynchronizer::fast_exit(obj, lock, THREAD);
|
||||
}
|
||||
ObjectSynchronizer::exit(obj, lock, THREAD);
|
||||
IF_TRACE_jvmci_3 {
|
||||
char type[O_BUFLEN];
|
||||
obj->klass()->name()->as_C_string(type, O_BUFLEN);
|
||||
|
||||
@ -25,12 +25,12 @@
|
||||
#ifndef SHARE_MEMORY_ALLOCATION_HPP
|
||||
#define SHARE_MEMORY_ALLOCATION_HPP
|
||||
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
#include <new>
|
||||
|
||||
class outputStream;
|
||||
class Thread;
|
||||
|
||||
class AllocFailStrategy {
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#define SHARE_MEMORY_ALLOCATION_INLINE_HPP
|
||||
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
|
||||
@ -55,6 +55,7 @@
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/classpathStream.hpp"
|
||||
#include "utilities/defaultStream.hpp"
|
||||
#if INCLUDE_G1GC
|
||||
#include "gc/g1/g1CollectedHeap.hpp"
|
||||
@ -240,7 +241,6 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
|
||||
// JVM version string ... changes on each build.
|
||||
get_header_version(_jvm_ident);
|
||||
|
||||
ClassLoaderExt::finalize_shared_paths_misc_info();
|
||||
_app_class_paths_start_index = ClassLoaderExt::app_class_paths_start_index();
|
||||
_app_module_paths_start_index = ClassLoaderExt::app_module_paths_start_index();
|
||||
_num_module_paths = ClassLoader::num_module_path_entries();
|
||||
@ -256,6 +256,11 @@ void FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment) {
|
||||
_base_archive_is_default = false;
|
||||
}
|
||||
|
||||
void SharedClassPathEntry::init_as_non_existent(const char* path, TRAPS) {
|
||||
_type = non_existent_entry;
|
||||
set_name(path, THREAD);
|
||||
}
|
||||
|
||||
void SharedClassPathEntry::init(bool is_modules_image,
|
||||
ClassPathEntry* cpe, TRAPS) {
|
||||
assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
|
||||
@ -287,26 +292,35 @@ void SharedClassPathEntry::init(bool is_modules_image,
|
||||
FileMapInfo::fail_stop("Unable to open file %s.", cpe->name());
|
||||
}
|
||||
|
||||
size_t len = strlen(cpe->name()) + 1;
|
||||
_name = MetadataFactory::new_array<char>(ClassLoaderData::the_null_class_loader_data(), (int)len, THREAD);
|
||||
strcpy(_name->data(), cpe->name());
|
||||
// No need to save the name of the module file, as it will be computed at run time
|
||||
// to allow relocation of the JDK directory.
|
||||
const char* name = is_modules_image ? "" : cpe->name();
|
||||
set_name(name, THREAD);
|
||||
}
|
||||
|
||||
bool SharedClassPathEntry::validate(bool is_class_path) {
|
||||
void SharedClassPathEntry::set_name(const char* name, TRAPS) {
|
||||
size_t len = strlen(name) + 1;
|
||||
_name = MetadataFactory::new_array<char>(ClassLoaderData::the_null_class_loader_data(), (int)len, THREAD);
|
||||
strcpy(_name->data(), name);
|
||||
}
|
||||
|
||||
const char* SharedClassPathEntry::name() const {
|
||||
if (UseSharedSpaces && is_modules_image()) {
|
||||
// In order to validate the runtime modules image file size against the archived
|
||||
// size information, we need to obtain the runtime modules image path. The recorded
|
||||
// dump time modules image path in the archive may be different from the runtime path
|
||||
// if the JDK image has beed moved after generating the archive.
|
||||
return ClassLoader::get_jrt_entry()->name();
|
||||
} else {
|
||||
return _name->data();
|
||||
}
|
||||
}
|
||||
|
||||
bool SharedClassPathEntry::validate(bool is_class_path) const {
|
||||
assert(UseSharedSpaces, "runtime only");
|
||||
|
||||
struct stat st;
|
||||
const char* name;
|
||||
|
||||
// In order to validate the runtime modules image file size against the archived
|
||||
// size information, we need to obtain the runtime modules image path. The recorded
|
||||
// dump time modules image path in the archive may be different from the runtime path
|
||||
// if the JDK image has beed moved after generating the archive.
|
||||
if (is_modules_image()) {
|
||||
name = ClassLoader::get_jrt_entry()->name();
|
||||
} else {
|
||||
name = this->name();
|
||||
}
|
||||
const char* name = this->name();
|
||||
|
||||
bool ok = true;
|
||||
log_info(class, path)("checking shared classpath entry: %s", name);
|
||||
@ -344,6 +358,19 @@ bool SharedClassPathEntry::validate(bool is_class_path) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool SharedClassPathEntry::check_non_existent() const {
|
||||
assert(_type == non_existent_entry, "must be");
|
||||
log_info(class, path)("should be non-existent: %s", name());
|
||||
struct stat st;
|
||||
if (os::stat(name(), &st) != 0) {
|
||||
log_info(class, path)("ok");
|
||||
return true; // file doesn't exist
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SharedClassPathEntry::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
it->push(&_name);
|
||||
it->push(&_manifest);
|
||||
@ -358,10 +385,11 @@ void SharedPathTable::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
|
||||
void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, Thread* THREAD) {
|
||||
size_t entry_size = sizeof(SharedClassPathEntry);
|
||||
int num_boot_classpath_entries = ClassLoader::num_boot_classpath_entries();
|
||||
int num_app_classpath_entries = ClassLoader::num_app_classpath_entries();
|
||||
int num_module_path_entries = ClassLoader::num_module_path_entries();
|
||||
int num_entries = num_boot_classpath_entries + num_app_classpath_entries + num_module_path_entries;
|
||||
int num_entries = 0;
|
||||
num_entries += ClassLoader::num_boot_classpath_entries();
|
||||
num_entries += ClassLoader::num_app_classpath_entries();
|
||||
num_entries += ClassLoader::num_module_path_entries();
|
||||
num_entries += FileMapInfo::num_non_existent_class_paths();
|
||||
size_t bytes = entry_size * num_entries;
|
||||
|
||||
_table = MetadataFactory::new_array<u8>(loader_data, (int)(bytes + 7 / 8), THREAD);
|
||||
@ -371,7 +399,7 @@ void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, Thread* THREAD
|
||||
void FileMapInfo::allocate_shared_path_table() {
|
||||
assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "Sanity");
|
||||
|
||||
Thread* THREAD = Thread::current();
|
||||
EXCEPTION_MARK; // The following calls should never throw, but would exit VM on error.
|
||||
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
|
||||
ClassPathEntry* jrt = ClassLoader::get_jrt_entry();
|
||||
|
||||
@ -382,47 +410,37 @@ void FileMapInfo::allocate_shared_path_table() {
|
||||
|
||||
// 1. boot class path
|
||||
int i = 0;
|
||||
ClassPathEntry* cpe = jrt;
|
||||
i = add_shared_classpaths(i, "boot", jrt, THREAD);
|
||||
i = add_shared_classpaths(i, "app", ClassLoader::app_classpath_entries(), THREAD);
|
||||
i = add_shared_classpaths(i, "module", ClassLoader::module_path_entries(), THREAD);
|
||||
|
||||
for (int x = 0; x < num_non_existent_class_paths(); x++, i++) {
|
||||
const char* path = _non_existent_class_paths->at(x);
|
||||
shared_path(i)->init_as_non_existent(path, THREAD);
|
||||
}
|
||||
|
||||
assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
|
||||
}
|
||||
|
||||
int FileMapInfo::add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS) {
|
||||
while (cpe != NULL) {
|
||||
bool is_jrt = (cpe == jrt);
|
||||
bool is_jrt = (cpe == ClassLoader::get_jrt_entry());
|
||||
const char* type = (is_jrt ? "jrt" : (cpe->is_jar_file() ? "jar" : "dir"));
|
||||
log_info(class, path)("add main shared path (%s) %s", type, cpe->name());
|
||||
log_info(class, path)("add %s shared path (%s) %s", which, type, cpe->name());
|
||||
SharedClassPathEntry* ent = shared_path(i);
|
||||
ent->init(is_jrt, cpe, THREAD);
|
||||
if (!is_jrt) { // No need to do the modules image.
|
||||
EXCEPTION_MARK; // The following call should never throw, but would exit VM on error.
|
||||
update_shared_classpath(cpe, ent, THREAD);
|
||||
if (cpe->is_jar_file()) {
|
||||
update_jar_manifest(cpe, ent, THREAD);
|
||||
}
|
||||
if (is_jrt) {
|
||||
cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
|
||||
} else {
|
||||
cpe = cpe->next();
|
||||
}
|
||||
cpe = ClassLoader::get_next_boot_classpath_entry(cpe);
|
||||
i++;
|
||||
}
|
||||
assert(i == ClassLoader::num_boot_classpath_entries(),
|
||||
"number of boot class path entry mismatch");
|
||||
|
||||
// 2. app class path
|
||||
ClassPathEntry *acpe = ClassLoader::app_classpath_entries();
|
||||
while (acpe != NULL) {
|
||||
log_info(class, path)("add app shared path %s", acpe->name());
|
||||
SharedClassPathEntry* ent = shared_path(i);
|
||||
ent->init(false, acpe, THREAD);
|
||||
EXCEPTION_MARK;
|
||||
update_shared_classpath(acpe, ent, THREAD);
|
||||
acpe = acpe->next();
|
||||
i++;
|
||||
}
|
||||
|
||||
// 3. module path
|
||||
ClassPathEntry *mpe = ClassLoader::module_path_entries();
|
||||
while (mpe != NULL) {
|
||||
log_info(class, path)("add module path %s",mpe->name());
|
||||
SharedClassPathEntry* ent = shared_path(i);
|
||||
ent->init(false, mpe, THREAD);
|
||||
EXCEPTION_MARK;
|
||||
update_shared_classpath(mpe, ent, THREAD);
|
||||
mpe = mpe->next();
|
||||
i++;
|
||||
}
|
||||
assert(i == _shared_path_table.size(), "number of shared path entry mismatch");
|
||||
return i;
|
||||
}
|
||||
|
||||
void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
|
||||
@ -452,6 +470,24 @@ void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
|
||||
}
|
||||
}
|
||||
|
||||
void FileMapInfo::record_non_existent_class_path_entry(const char* path) {
|
||||
assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
|
||||
log_info(class, path)("non-existent Class-Path entry %s", path);
|
||||
if (_non_existent_class_paths == NULL) {
|
||||
_non_existent_class_paths = new (ResourceObj::C_HEAP, mtInternal)GrowableArray<const char*>(10, true);
|
||||
}
|
||||
_non_existent_class_paths->append(os::strdup(path));
|
||||
}
|
||||
|
||||
int FileMapInfo::num_non_existent_class_paths() {
|
||||
assert(DumpSharedSpaces || DynamicDumpSharedSpaces, "dump time only");
|
||||
if (_non_existent_class_paths != NULL) {
|
||||
return _non_existent_class_paths->length();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class ManifestStream: public ResourceObj {
|
||||
private:
|
||||
u1* _buffer_start; // Buffer bottom
|
||||
@ -500,29 +536,27 @@ class ManifestStream: public ResourceObj {
|
||||
}
|
||||
};
|
||||
|
||||
void FileMapInfo::update_shared_classpath(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS) {
|
||||
void FileMapInfo::update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS) {
|
||||
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
|
||||
ResourceMark rm(THREAD);
|
||||
jint manifest_size;
|
||||
|
||||
if (cpe->is_jar_file()) {
|
||||
assert(ent->is_jar(), "the shared class path entry is not a JAR file");
|
||||
char* manifest = ClassLoaderExt::read_manifest(cpe, &manifest_size, CHECK);
|
||||
if (manifest != NULL) {
|
||||
ManifestStream* stream = new ManifestStream((u1*)manifest,
|
||||
manifest_size);
|
||||
if (stream->check_is_signed()) {
|
||||
ent->set_is_signed();
|
||||
} else {
|
||||
// Copy the manifest into the shared archive
|
||||
manifest = ClassLoaderExt::read_raw_manifest(cpe, &manifest_size, CHECK);
|
||||
Array<u1>* buf = MetadataFactory::new_array<u1>(loader_data,
|
||||
manifest_size,
|
||||
THREAD);
|
||||
char* p = (char*)(buf->data());
|
||||
memcpy(p, manifest, manifest_size);
|
||||
ent->set_manifest(buf);
|
||||
}
|
||||
assert(cpe->is_jar_file() && ent->is_jar(), "the shared class path entry is not a JAR file");
|
||||
char* manifest = ClassLoaderExt::read_manifest(cpe, &manifest_size, CHECK);
|
||||
if (manifest != NULL) {
|
||||
ManifestStream* stream = new ManifestStream((u1*)manifest,
|
||||
manifest_size);
|
||||
if (stream->check_is_signed()) {
|
||||
ent->set_is_signed();
|
||||
} else {
|
||||
// Copy the manifest into the shared archive
|
||||
manifest = ClassLoaderExt::read_raw_manifest(cpe, &manifest_size, CHECK);
|
||||
Array<u1>* buf = MetadataFactory::new_array<u1>(loader_data,
|
||||
manifest_size,
|
||||
THREAD);
|
||||
char* p = (char*)(buf->data());
|
||||
memcpy(p, manifest, manifest_size);
|
||||
ent->set_manifest(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -566,32 +600,16 @@ int FileMapInfo::num_paths(const char* path) {
|
||||
return npaths;
|
||||
}
|
||||
|
||||
GrowableArray<char*>* FileMapInfo::create_path_array(const char* path) {
|
||||
GrowableArray<char*>* path_array = new(ResourceObj::RESOURCE_AREA, mtInternal)
|
||||
GrowableArray<char*>(10);
|
||||
char* begin_ptr = (char*)path;
|
||||
char* end_ptr = strchr((char*)path, os::path_separator()[0]);
|
||||
if (end_ptr == NULL) {
|
||||
end_ptr = strchr((char*)path, '\0');
|
||||
}
|
||||
while (end_ptr != NULL) {
|
||||
if ((end_ptr - begin_ptr) > 1) {
|
||||
struct stat st;
|
||||
char* temp_name = NEW_RESOURCE_ARRAY(char, (size_t)(end_ptr - begin_ptr + 1));
|
||||
strncpy(temp_name, begin_ptr, end_ptr - begin_ptr);
|
||||
temp_name[end_ptr - begin_ptr] = '\0';
|
||||
if (os::stat(temp_name, &st) == 0) {
|
||||
path_array->append(temp_name);
|
||||
}
|
||||
}
|
||||
if (end_ptr < (path + strlen(path))) {
|
||||
begin_ptr = ++end_ptr;
|
||||
end_ptr = strchr(begin_ptr, os::path_separator()[0]);
|
||||
if (end_ptr == NULL) {
|
||||
end_ptr = strchr(begin_ptr, '\0');
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
GrowableArray<const char*>* FileMapInfo::create_path_array(const char* paths) {
|
||||
GrowableArray<const char*>* path_array = new(ResourceObj::RESOURCE_AREA, mtInternal)
|
||||
GrowableArray<const char*>(10);
|
||||
|
||||
ClasspathStream cp_stream(paths);
|
||||
while (cp_stream.has_next()) {
|
||||
const char* path = cp_stream.get_next();
|
||||
struct stat st;
|
||||
if (os::stat(path, &st) == 0) {
|
||||
path_array->append(path);
|
||||
}
|
||||
}
|
||||
return path_array;
|
||||
@ -603,7 +621,7 @@ bool FileMapInfo::fail(const char* msg, const char* name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileMapInfo::check_paths(int shared_path_start_idx, int num_paths, GrowableArray<char*>* rp_array) {
|
||||
bool FileMapInfo::check_paths(int shared_path_start_idx, int num_paths, GrowableArray<const char*>* rp_array) {
|
||||
int i = 0;
|
||||
int j = shared_path_start_idx;
|
||||
bool mismatch = false;
|
||||
@ -657,7 +675,7 @@ bool FileMapInfo::validate_boot_class_paths() {
|
||||
} else if (dp_len > 0 && rp != NULL) {
|
||||
int num;
|
||||
ResourceMark rm;
|
||||
GrowableArray<char*>* rp_array = create_path_array(rp);
|
||||
GrowableArray<const char*>* rp_array = create_path_array(rp);
|
||||
int rp_len = rp_array->length();
|
||||
if (rp_len >= dp_len) {
|
||||
if (relaxed_check) {
|
||||
@ -690,11 +708,21 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
|
||||
if (shared_app_paths_len != 0 && rp_len != 0) {
|
||||
// Prefix is OK: E.g., dump with -cp foo.jar, but run with -cp foo.jar:bar.jar.
|
||||
ResourceMark rm;
|
||||
GrowableArray<char*>* rp_array = create_path_array(appcp);
|
||||
GrowableArray<const char*>* rp_array = create_path_array(appcp);
|
||||
if (rp_array->length() == 0) {
|
||||
// None of the jar file specified in the runtime -cp exists.
|
||||
return fail("None of the jar file specified in the runtime -cp exists: -Djava.class.path=", appcp);
|
||||
}
|
||||
|
||||
// Handling of non-existent entries in the classpath: we eliminate all the non-existent
|
||||
// entries from both the dump time classpath (ClassLoader::update_class_path_entry_list)
|
||||
// and the runtime classpath (FileMapInfo::create_path_array), and check the remaining
|
||||
// entries. E.g.:
|
||||
//
|
||||
// dump : -cp a.jar:NE1:NE2:b.jar -> a.jar:b.jar -> recorded in archive.
|
||||
// run 1: -cp NE3:a.jar:NE4:b.jar -> a.jar:b.jar -> matched
|
||||
// run 2: -cp x.jar:NE4:b.jar -> x.jar:b.jar -> mismatched
|
||||
|
||||
int j = _header->_app_class_paths_start_index;
|
||||
mismatch = check_paths(j, shared_app_paths_len, rp_array);
|
||||
if (mismatch) {
|
||||
@ -704,6 +732,20 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) {
|
||||
LogTarget(Info, class, path) lt;
|
||||
if (lt.is_enabled()) {
|
||||
LogStream ls(lt);
|
||||
ls.print("%s", msg);
|
||||
const char* prefix = "";
|
||||
for (int i = start_idx; i < end_idx; i++) {
|
||||
ls.print("%s%s", prefix, shared_path(i)->name());
|
||||
prefix = os::path_separator();
|
||||
}
|
||||
ls.cr();
|
||||
}
|
||||
}
|
||||
|
||||
bool FileMapInfo::validate_shared_path_table() {
|
||||
assert(UseSharedSpaces, "runtime only");
|
||||
|
||||
@ -732,6 +774,9 @@ bool FileMapInfo::validate_shared_path_table() {
|
||||
}
|
||||
}
|
||||
|
||||
log_paths("Expecting BOOT path=", 0, _header->_app_class_paths_start_index);
|
||||
log_paths("Expecting -Djava.class.path=", _header->_app_class_paths_start_index, _header->_app_module_paths_start_index);
|
||||
|
||||
int module_paths_start_index = _header->_app_module_paths_start_index;
|
||||
int shared_app_paths_len = 0;
|
||||
|
||||
@ -772,6 +817,8 @@ bool FileMapInfo::validate_shared_path_table() {
|
||||
}
|
||||
}
|
||||
|
||||
validate_non_existent_class_paths();
|
||||
|
||||
_validating_shared_path_table = false;
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
@ -786,6 +833,26 @@ bool FileMapInfo::validate_shared_path_table() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void FileMapInfo::validate_non_existent_class_paths() {
|
||||
// All of the recorded non-existent paths came from the Class-Path: attribute from the JAR
|
||||
// files on the app classpath. If any of these are found to exist during runtime,
|
||||
// it will change how classes are loading for the app loader. For safety, disable
|
||||
// loading of archived platform/app classes (currently there's no way to disable just the
|
||||
// app classes).
|
||||
|
||||
assert(UseSharedSpaces, "runtime only");
|
||||
for (int i = _header->_app_module_paths_start_index + _header->_num_module_paths;
|
||||
i < get_number_of_shared_paths();
|
||||
i++) {
|
||||
SharedClassPathEntry* ent = shared_path(i);
|
||||
if (!ent->check_non_existent()) {
|
||||
warning("Archived non-system classes are disabled because the "
|
||||
"file %s exists", ent->name());
|
||||
_header->_has_platform_or_app_classes = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FileMapInfo::check_archive(const char* archive_name, bool is_static) {
|
||||
int fd = os::open(archive_name, O_RDONLY | O_BINARY, 0);
|
||||
if (fd < 0) {
|
||||
@ -855,9 +922,6 @@ bool FileMapInfo::get_base_archive_name_from_header(const char* archive_name,
|
||||
if (dynamic_header->_base_archive_is_default) {
|
||||
*base_archive_name = Arguments::get_default_shared_archive_path();
|
||||
} else {
|
||||
// skip over the _paths_misc_info
|
||||
sz = dynamic_header->_paths_misc_info_size;
|
||||
lseek(fd, (long)sz, SEEK_CUR);
|
||||
// read the base archive name
|
||||
size_t name_size = dynamic_header->_base_archive_name_size;
|
||||
if (name_size == 0) {
|
||||
@ -948,18 +1012,7 @@ bool FileMapInfo::init_from_file(int fd, bool is_static) {
|
||||
}
|
||||
}
|
||||
|
||||
_file_offset = n;
|
||||
|
||||
size_t info_size = _header->_paths_misc_info_size;
|
||||
_paths_misc_info = NEW_C_HEAP_ARRAY(char, info_size, mtClass);
|
||||
n = os::read(fd, _paths_misc_info, (unsigned int)info_size);
|
||||
if (n != info_size) {
|
||||
fail_continue("Unable to read the shared path info header.");
|
||||
FREE_C_HEAP_ARRAY(char, _paths_misc_info);
|
||||
_paths_misc_info = NULL;
|
||||
return false;
|
||||
}
|
||||
_file_offset += n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name
|
||||
_file_offset = n + _header->_base_archive_name_size; // accounts for the size of _base_archive_name
|
||||
|
||||
if (is_static) {
|
||||
// just checking the last region is sufficient since the archive is written
|
||||
@ -1041,10 +1094,6 @@ void FileMapInfo::open_for_write(const char* path) {
|
||||
// Write the header to the file, seek to the next allocation boundary.
|
||||
|
||||
void FileMapInfo::write_header() {
|
||||
int info_size = ClassLoader::get_shared_paths_misc_info_size();
|
||||
|
||||
_header->_paths_misc_info_size = info_size;
|
||||
|
||||
char* base_archive_name = NULL;
|
||||
if (_header->_magic == CDS_DYNAMIC_ARCHIVE_MAGIC) {
|
||||
base_archive_name = (char*)Arguments::GetSharedArchivePath();
|
||||
@ -1054,7 +1103,6 @@ void FileMapInfo::write_header() {
|
||||
|
||||
assert(is_file_position_aligned(), "must be");
|
||||
write_bytes(_header, _header->_header_size);
|
||||
write_bytes(ClassLoader::get_shared_paths_misc_info(), (size_t)info_size);
|
||||
if (base_archive_name != NULL) {
|
||||
write_bytes(base_archive_name, (size_t)_header->_base_archive_name_size);
|
||||
}
|
||||
@ -1743,6 +1791,7 @@ bool FileMapInfo::_heap_pointers_need_patching = false;
|
||||
SharedPathTable FileMapInfo::_shared_path_table;
|
||||
bool FileMapInfo::_validating_shared_path_table = false;
|
||||
bool FileMapInfo::_memory_mapping_failed = false;
|
||||
GrowableArray<const char*>* FileMapInfo::_non_existent_class_paths = NULL;
|
||||
|
||||
// Open the shared archive file, read and validate the header
|
||||
// information (version, boot classpath, etc.). If initialization
|
||||
@ -1751,7 +1800,7 @@ bool FileMapInfo::_memory_mapping_failed = false;
|
||||
//
|
||||
// Validation of the archive is done in two steps:
|
||||
//
|
||||
// [1] validate_header() - done here. This checks the header, including _paths_misc_info.
|
||||
// [1] validate_header() - done here.
|
||||
// [2] validate_shared_path_table - this is done later, because the table is in the RW
|
||||
// region of the archive, which is not mapped yet.
|
||||
bool FileMapInfo::initialize(bool is_static) {
|
||||
@ -1855,22 +1904,7 @@ bool FileMapHeader::validate() {
|
||||
}
|
||||
|
||||
bool FileMapInfo::validate_header(bool is_static) {
|
||||
bool status = _header->validate();
|
||||
|
||||
if (status) {
|
||||
if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size, is_static)) {
|
||||
if (!PrintSharedArchiveAndExit) {
|
||||
fail_continue("shared class paths mismatch (hint: enable -Xlog:class+path=info to diagnose the failure)");
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_paths_misc_info != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, _paths_misc_info);
|
||||
_paths_misc_info = NULL;
|
||||
}
|
||||
return status;
|
||||
return _header->validate();
|
||||
}
|
||||
|
||||
// Check if a given address is within one of the shared regions
|
||||
@ -1922,7 +1956,7 @@ ClassPathEntry* FileMapInfo::get_classpath_entry_for_jvmti(int i, TRAPS) {
|
||||
ClassPathEntry* ent = _classpath_entries_for_jvmti[i];
|
||||
if (ent == NULL) {
|
||||
if (i == 0) {
|
||||
ent = ClassLoader:: get_jrt_entry();
|
||||
ent = ClassLoader::get_jrt_entry();
|
||||
assert(ent != NULL, "must be");
|
||||
} else {
|
||||
SharedClassPathEntry* scpe = shared_path(i);
|
||||
|
||||
@ -49,8 +49,12 @@ class SharedClassPathEntry {
|
||||
jar_entry,
|
||||
signed_jar_entry,
|
||||
dir_entry,
|
||||
non_existent_entry,
|
||||
unknown_entry
|
||||
};
|
||||
|
||||
void set_name(const char* name, TRAPS);
|
||||
|
||||
protected:
|
||||
u1 _type;
|
||||
bool _from_class_path_attr;
|
||||
@ -61,24 +65,25 @@ protected:
|
||||
|
||||
public:
|
||||
void init(bool is_modules_image, ClassPathEntry* cpe, TRAPS);
|
||||
void init_as_non_existent(const char* path, TRAPS);
|
||||
void metaspace_pointers_do(MetaspaceClosure* it);
|
||||
bool validate(bool is_class_path = true);
|
||||
bool validate(bool is_class_path = true) const;
|
||||
|
||||
// The _timestamp only gets set for jar files.
|
||||
bool has_timestamp() {
|
||||
bool has_timestamp() const {
|
||||
return _timestamp != 0;
|
||||
}
|
||||
bool is_dir() { return _type == dir_entry; }
|
||||
bool is_modules_image() { return _type == modules_image_entry; }
|
||||
bool is_jar() { return _type == jar_entry; }
|
||||
bool is_signed() { return _type == signed_jar_entry; }
|
||||
void set_is_signed() {
|
||||
bool is_dir() const { return _type == dir_entry; }
|
||||
bool is_modules_image() const { return _type == modules_image_entry; }
|
||||
bool is_jar() const { return _type == jar_entry; }
|
||||
bool is_signed() const { return _type == signed_jar_entry; }
|
||||
void set_is_signed() {
|
||||
_type = signed_jar_entry;
|
||||
}
|
||||
bool from_class_path_attr() { return _from_class_path_attr; }
|
||||
time_t timestamp() const { return _timestamp; }
|
||||
long filesize() const { return _filesize; }
|
||||
const char* name() const { return _name->data(); }
|
||||
const char* name() const;
|
||||
const char* manifest() const {
|
||||
return (_manifest == NULL) ? NULL : (const char*)_manifest->data();
|
||||
}
|
||||
@ -88,6 +93,7 @@ public:
|
||||
void set_manifest(Array<u1>* manifest) {
|
||||
_manifest = manifest;
|
||||
}
|
||||
bool check_non_existent() const;
|
||||
};
|
||||
|
||||
struct ArchiveHeapOopmapInfo {
|
||||
@ -147,30 +153,12 @@ struct FileMapHeader : public CDSFileMapHeaderBase {
|
||||
// size of the base archive name including NULL terminator
|
||||
int _base_archive_name_size;
|
||||
|
||||
// The _paths_misc_info is a variable-size structure that records "miscellaneous"
|
||||
// information during dumping. It is generated and validated by the
|
||||
// SharedPathsMiscInfo class. See SharedPathsMiscInfo.hpp for
|
||||
// detailed description.
|
||||
//
|
||||
// The _paths_misc_info data is stored as a byte array in the archive file header,
|
||||
// immediately after the _header field. This information is used only when
|
||||
// checking the validity of the archive and is deallocated after the archive is loaded.
|
||||
//
|
||||
// Note that the _paths_misc_info does NOT include information for JAR files
|
||||
// that existed during dump time. Their information is stored in _shared_path_table.
|
||||
int _paths_misc_info_size;
|
||||
|
||||
// The following is a table of all the class path entries that were used
|
||||
// during dumping. At run time, we require these files to exist and have the same
|
||||
// size/modification time, or else the archive will refuse to load.
|
||||
//
|
||||
// All of these entries must be JAR files. The dumping process would fail if a non-empty
|
||||
// directory was specified in the classpaths. If an empty directory was specified
|
||||
// it is checked by the _paths_misc_info as described above.
|
||||
//
|
||||
// FIXME -- if JAR files in the tail of the list were specified but not used during dumping,
|
||||
// they should be removed from this table, to save space and to avoid spurious
|
||||
// loading failures during runtime.
|
||||
// The following is a table of all the boot/app/module path entries that were used
|
||||
// during dumping. At run time, we validate these entries according to their
|
||||
// SharedClassPathEntry::_type. See:
|
||||
// check_nonempty_dir_in_shared_path_table()
|
||||
// validate_shared_path_table()
|
||||
// validate_non_existent_class_paths()
|
||||
SharedPathTable _shared_path_table;
|
||||
|
||||
jshort _app_class_paths_start_index; // Index of first app classpath entry
|
||||
@ -232,13 +220,14 @@ public:
|
||||
FileMapHeader * _header;
|
||||
|
||||
const char* _full_path;
|
||||
char* _paths_misc_info;
|
||||
char* _base_archive_name;
|
||||
|
||||
static FileMapInfo* _current_info;
|
||||
static FileMapInfo* _dynamic_archive_info;
|
||||
static bool _heap_pointers_need_patching;
|
||||
static bool _memory_mapping_failed;
|
||||
static GrowableArray<const char*>* _non_existent_class_paths;
|
||||
|
||||
static bool get_base_archive_name_from_header(const char* archive_name,
|
||||
int* size, char** base_archive_name);
|
||||
static bool check_archive(const char* archive_name, bool is_static);
|
||||
@ -246,6 +235,8 @@ public:
|
||||
bool init_from_file(int fd, bool is_static);
|
||||
static void metaspace_pointers_do(MetaspaceClosure* it);
|
||||
|
||||
void log_paths(const char* msg, int start_idx, int end_idx);
|
||||
|
||||
public:
|
||||
FileMapInfo(bool is_static);
|
||||
~FileMapInfo();
|
||||
@ -353,9 +344,13 @@ public:
|
||||
static void stop_sharing_and_unmap(const char* msg);
|
||||
|
||||
static void allocate_shared_path_table();
|
||||
static int add_shared_classpaths(int i, const char* which, ClassPathEntry *cpe, TRAPS);
|
||||
static void check_nonempty_dir_in_shared_path_table();
|
||||
bool validate_shared_path_table();
|
||||
static void update_shared_classpath(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS);
|
||||
void validate_non_existent_class_paths();
|
||||
static void update_jar_manifest(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS);
|
||||
static int num_non_existent_class_paths();
|
||||
static void record_non_existent_class_path_entry(const char* path);
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
static ClassFileStream* open_stream_for_jvmti(InstanceKlass* ik, Handle class_loader, TRAPS);
|
||||
@ -379,11 +374,10 @@ public:
|
||||
private:
|
||||
char* skip_first_path_entry(const char* path) NOT_CDS_RETURN_(NULL);
|
||||
int num_paths(const char* path) NOT_CDS_RETURN_(0);
|
||||
GrowableArray<char*>* create_path_array(const char* path) NOT_CDS_RETURN_(NULL);
|
||||
GrowableArray<const char*>* create_path_array(const char* path) NOT_CDS_RETURN_(NULL);
|
||||
bool fail(const char* msg, const char* name) NOT_CDS_RETURN_(false);
|
||||
bool check_paths(int shared_path_start_idx,
|
||||
int num_paths,
|
||||
GrowableArray<char*>* rp_array) NOT_CDS_RETURN_(false);
|
||||
bool check_paths(int shared_path_start_idx, int num_paths,
|
||||
GrowableArray<const char*>* rp_array) NOT_CDS_RETURN_(false);
|
||||
bool validate_boot_class_paths() NOT_CDS_RETURN_(false);
|
||||
bool validate_app_class_paths(int shared_app_paths_len) NOT_CDS_RETURN_(false);
|
||||
bool map_heap_data(MemRegion **heap_mem, int first, int max, int* num,
|
||||
|
||||
@ -79,6 +79,7 @@ static ArchivableStaticFieldInfo open_archive_subgraph_entry_fields[] = {
|
||||
{"java/util/ImmutableCollections$MapN", "EMPTY_MAP"},
|
||||
{"java/util/ImmutableCollections$SetN", "EMPTY_SET"},
|
||||
{"java/lang/module/Configuration", "EMPTY_CONFIGURATION"},
|
||||
{"jdk/internal/math/FDBigInteger", "archivedCaches"},
|
||||
};
|
||||
|
||||
const static int num_closed_archive_subgraph_entry_fields =
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "memory/metaspaceChunkFreeListSummary.hpp"
|
||||
#include "memory/virtualspace.hpp"
|
||||
#include "memory/metaspace/metaspaceSizesSnapshot.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/exceptions.hpp"
|
||||
|
||||
// Metaspace
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
#include "metaprogramming/isVolatile.hpp"
|
||||
#include "oops/accessDecorators.hpp"
|
||||
#include "oops/oopsHierarchy.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
|
||||
@ -946,7 +946,7 @@ void InstanceKlass::initialize_impl(TRAPS) {
|
||||
while (is_being_initialized() && !is_reentrant_initialization(jt)) {
|
||||
wait = true;
|
||||
jt->set_class_to_be_initialized(this);
|
||||
ol.waitUninterruptibly(jt);
|
||||
ol.wait_uninterruptibly(jt);
|
||||
jt->set_class_to_be_initialized(NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "metaprogramming/integralConstant.hpp"
|
||||
#include "metaprogramming/primitiveConversions.hpp"
|
||||
#include "oops/oopsHierarchy.hpp"
|
||||
#include "runtime/globals.hpp"
|
||||
|
||||
// The markWord describes the header of an object.
|
||||
//
|
||||
|
||||
@ -173,35 +173,6 @@ void* oopDesc::load_oop_raw(oop obj, int offset) {
|
||||
}
|
||||
}
|
||||
|
||||
bool oopDesc::is_valid(oop obj) {
|
||||
if (!is_object_aligned(obj)) return false;
|
||||
if ((size_t)(oopDesc*)obj < os::min_page_size()) return false;
|
||||
|
||||
// We need at least the mark and the klass word in the committed region.
|
||||
if (!os::is_readable_range(obj, (oopDesc*)obj + 1)) return false;
|
||||
if (!Universe::heap()->is_in(obj)) return false;
|
||||
|
||||
Klass* k = (Klass*)load_klass_raw(obj);
|
||||
return Klass::is_valid(k);
|
||||
}
|
||||
|
||||
oop oopDesc::oop_or_null(address addr) {
|
||||
if (is_valid(oop(addr))) {
|
||||
// We were just given an oop directly.
|
||||
return oop(addr);
|
||||
}
|
||||
|
||||
// Try to find addr using block_start.
|
||||
HeapWord* p = Universe::heap()->block_start(addr);
|
||||
if (p != NULL && Universe::heap()->block_is_obj(p)) {
|
||||
if (!is_valid(oop(p))) return NULL;
|
||||
return oop(p);
|
||||
}
|
||||
|
||||
// If we can't find it it just may mean that heap wasn't parsable.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
oop oopDesc::obj_field_acquire(int offset) const { return HeapAccess<MO_ACQUIRE>::oop_load_at(as_oop(), offset); }
|
||||
|
||||
void oopDesc::obj_field_put_raw(int offset, oop value) { RawAccess<>::oop_store_at(as_oop(), offset, value); }
|
||||
|
||||
@ -331,8 +331,6 @@ class oopDesc {
|
||||
// for error reporting
|
||||
static void* load_klass_raw(oop obj);
|
||||
static void* load_oop_raw(oop obj, int offset);
|
||||
static bool is_valid(oop obj);
|
||||
static oop oop_or_null(address addr);
|
||||
};
|
||||
|
||||
#endif // SHARE_OOPS_OOP_HPP
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user