--- a/hotspot/make/lib/JvmFeatures.gmk Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/make/lib/JvmFeatures.gmk Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2017, 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
@@ -88,11 +88,6 @@
JVM_EXCLUDE_FILES += jvmciCodeInstaller_$(HOTSPOT_TARGET_CPU_ARCH).cpp
endif
-ifneq ($(call check-jvm-feature, fprof), true)
- JVM_CFLAGS_FEATURES += -DINCLUDE_FPROF=0
- JVM_EXCLUDE_FILES += fprofiler.cpp
-endif
-
ifneq ($(call check-jvm-feature, vm-structs), true)
JVM_CFLAGS_FEATURES += -DINCLUDE_VM_STRUCTS=0
JVM_EXCLUDE_FILES += vmStructs.cpp
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -3630,6 +3630,12 @@
}
#if INCLUDE_ALL_GCS
+/*
+ * g1_write_barrier_pre -- G1GC pre-write barrier for store of new_val at
+ * store_addr.
+ *
+ * Allocates rscratch1
+ */
void MacroAssembler::g1_write_barrier_pre(Register obj,
Register pre_val,
Register thread,
@@ -3645,10 +3651,8 @@
Label done;
Label runtime;
- assert(pre_val != noreg, "check this code");
-
- if (obj != noreg)
- assert_different_registers(obj, pre_val, tmp);
+ assert_different_registers(obj, pre_val, tmp, rscratch1);
+ assert(pre_val != noreg && tmp != noreg, "expecting a register");
Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
SATBMarkQueue::byte_offset_of_active()));
@@ -3722,12 +3726,22 @@
bind(done);
}
+/*
+ * g1_write_barrier_post -- G1GC post-write barrier for store of new_val at
+ * store_addr
+ *
+ * Allocates rscratch1
+ */
void MacroAssembler::g1_write_barrier_post(Register store_addr,
Register new_val,
Register thread,
Register tmp,
Register tmp2) {
assert(thread == rthread, "must be");
+ assert_different_registers(store_addr, new_val, thread, tmp, tmp2,
+ rscratch1);
+ assert(store_addr != noreg && new_val != noreg && tmp != noreg
+ && tmp2 != noreg, "expecting a register");
Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
DirtyCardQueue::byte_offset_of_index()));
--- a/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/cpu/aarch64/vm/sharedRuntime_aarch64.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -2067,7 +2067,7 @@
__ g1_write_barrier_pre(noreg /* obj */,
r0 /* pre_val */,
rthread /* thread */,
- rscratch1 /* tmp */,
+ rscratch2 /* tmp */,
true /* tosca_live */,
true /* expand_call */);
}
--- a/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -170,7 +170,7 @@
// G1 barrier needs uncompressed oop for region cross check.
Register new_val = val;
if (UseCompressedOops) {
- new_val = rscratch1;
+ new_val = rscratch2;
__ mov(new_val, val);
}
__ store_heap_oop(Address(r3, 0), val);
--- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -292,7 +292,7 @@
if (VerifyThread) {
// NOTE: this chops off the heads of the 64-bit O registers.
// make sure G2_thread contains the right value
- save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod for -Xprof)
+ save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod)
mov(G1, L1); // avoid clobbering G1
// G2 saved below
mov(G3, L3); // avoid clobbering G3
@@ -398,7 +398,7 @@
#ifdef ASSERT
// check that it WAS previously set
- save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame for -Xprof
+ save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame
ld_ptr(sp_addr, L0);
tst(L0);
breakpoint_trap(Assembler::zero, Assembler::ptr_cc);
@@ -618,7 +618,7 @@
# ifdef ASSERT
// Check that we are not overwriting any other oop.
- save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod for -Xprof
+ save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod
ld_ptr(vm_result_addr, L0);
tst(L0);
restore();
--- a/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/cpu/sparc/vm/templateTable_sparc.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -2928,7 +2928,7 @@
__ br(Assembler::zero, false, Assembler::pt, notFinal);
__ delayed()->and3(Rret, 0xFF, G4_scratch); // gets number of parameters
- if (RewriteBytecodes && !UseSharedSpaces) {
+ if (RewriteBytecodes && !UseSharedSpaces && !DumpSharedSpaces) {
patch_bytecode(Bytecodes::_fast_invokevfinal, Rscratch, Rtemp);
}
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java Sun Sep 03 14:19:45 2017 +0200
@@ -187,10 +187,9 @@
{"StubRoutines::_arrayof_oop_disjoint_arraycopy", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy"},
{"StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit", "_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit"},
- {"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
+ {"StubRoutines::_unsafe_arraycopy", "_aot_stub_routines_unsafe_arraycopy"},
-
-
+ {"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
{"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"},
{"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"},
@@ -478,8 +477,8 @@
}
/**
- * Creates a global symbol of the form {@code "A" + container name}.
- * Note, linker on Windows does not allow names which start with '.'
+ * Creates a global symbol of the form {@code "A" + container name}. Note, linker on Windows
+ * does not allow names which start with '.'
*
* @param container container to create a symbol for
*/
@@ -685,7 +684,8 @@
}
/**
- * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to patch.
+ * Add oop symbol by as follows. Extend the oop.got section with another slot for the VM to
+ * patch.
*
* @param oopName name of the oop symbol
*/
@@ -728,10 +728,9 @@
}
/**
- * Add klass symbol by as follows.
- * - Adding the symbol name to the metaspace.names section
- * - Add the offset of the name in metaspace.names to metaspace.offsets
- * - Extend the klasses.got section with another slot for the VM to patch
+ * Add klass symbol by as follows. - Adding the symbol name to the metaspace.names section - Add
+ * the offset of the name in metaspace.names to metaspace.offsets - Extend the klasses.got
+ * section with another slot for the VM to patch
*
* @param klassName name of the metaspace symbol
* @return the got offset in the klasses.got of the metaspace symbol
--- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java Sun Sep 03 14:19:45 2017 +0200
@@ -27,6 +27,8 @@
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.core.GraalCompiler;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.hotspot.HotSpotBackend;
import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
@@ -127,7 +129,13 @@
ProfilingInfo profilingInfo = DefaultProfilingInfo.get(TriState.FALSE);
final boolean isImmutablePIC = true;
- CompilationResult compilationResult = new CompilationResult(resolvedMethod.getName(), isImmutablePIC);
+ CompilationIdentifier id = new CompilationIdentifier() {
+ @Override
+ public String toString(Verbosity verbosity) {
+ return resolvedMethod.getName();
+ }
+ };
+ CompilationResult compilationResult = new CompilationResult(id, isImmutablePIC);
return GraalCompiler.compileGraph(graph, resolvedMethod, providers, backend, graphBuilderSuite, OptimisticOptimizations.ALL, profilingInfo, getSuites(), getLirSuites(),
compilationResult, CompilationResultBuilderFactory.Default);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/ClassSubstitution.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/ClassSubstitution.java Sun Sep 03 14:19:45 2017 +0200
@@ -57,7 +57,9 @@
/**
* Determines if the substitutions are for classes that may not be part of the runtime.
- * Substitutions for such classes are omitted if the original classes cannot be found.
+ * Substitutions for such classes are omitted if the original classes cannot be found. If
+ * multiple classes are specified using {@link #className()} and {@link #optional()} is false,
+ * then at least one of the classes is required to be reachable.
*/
boolean optional() default false;
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.test/src/org/graalvm/compiler/asm/test/AssemblerTest.java Sun Sep 03 14:19:45 2017 +0200
@@ -90,7 +90,7 @@
StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(method).compilationId(compilationId).build();
CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, graph, null).getCallingConvention();
- CompilationResult compResult = new CompilationResult();
+ CompilationResult compResult = new CompilationResult(graph.compilationId());
byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);
compResult.setTargetCode(targetCode, targetCode.length);
compResult.setTotalFrameSize(0);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java Sun Sep 03 14:19:45 2017 +0200
@@ -33,6 +33,7 @@
import java.util.List;
import java.util.Objects;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.util.EconomicSet;
@@ -190,6 +191,8 @@
private final String name;
+ private final CompilationIdentifier compilationId;
+
/**
* The buffer containing the emitted machine code.
*/
@@ -222,21 +225,26 @@
private boolean isImmutablePIC;
- public CompilationResult() {
- this(null, false);
+ public CompilationResult(CompilationIdentifier compilationId) {
+ this(compilationId, compilationId.toString(CompilationIdentifier.Verbosity.NAME), false);
+ }
+
+ public CompilationResult(CompilationIdentifier compilationId, String name) {
+ this(compilationId, name, false);
+ }
+
+ public CompilationResult(CompilationIdentifier compilationId, boolean isImmutablePIC) {
+ this(compilationId, null, isImmutablePIC);
+ }
+
+ public CompilationResult(CompilationIdentifier compilationId, String name, boolean isImmutablePIC) {
+ this.compilationId = compilationId;
+ this.name = name;
+ this.isImmutablePIC = isImmutablePIC;
}
public CompilationResult(String name) {
- this(name, false);
- }
-
- public CompilationResult(boolean isImmutablePIC) {
- this(null, isImmutablePIC);
- }
-
- public CompilationResult(String name, boolean isImmutablePIC) {
- this.name = name;
- this.isImmutablePIC = isImmutablePIC;
+ this(null, name);
}
@Override
@@ -266,6 +274,7 @@
this.totalFrameSize == that.totalFrameSize &&
this.targetCodeSize == that.targetCodeSize &&
Objects.equals(this.name, that.name) &&
+ Objects.equals(this.compilationId, that.compilationId) &&
Objects.equals(this.annotations, that.annotations) &&
Objects.equals(this.dataSection, that.dataSection) &&
Objects.equals(this.exceptionHandlers, that.exceptionHandlers) &&
@@ -670,6 +679,10 @@
return name;
}
+ public CompilationIdentifier getCompilationId() {
+ return compilationId;
+ }
+
public void setHasUnsafeAccess(boolean hasUnsafeAccess) {
checkOpen();
this.hasUnsafeAccess = hasUnsafeAccess;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Sun Sep 03 14:19:45 2017 +0200
@@ -949,7 +949,7 @@
try (AllocSpy spy = AllocSpy.open(installedCodeOwner); DebugContext.Scope ds = debug.scope("Compiling", new DebugDumpScope(id.toString(CompilationIdentifier.Verbosity.ID), true))) {
CompilationPrinter printer = CompilationPrinter.begin(options, id, installedCodeOwner, INVOCATION_ENTRY_BCI);
- CompilationResult compResult = compile(installedCodeOwner, graphToCompile, new CompilationResult(), id, options);
+ CompilationResult compResult = compile(installedCodeOwner, graphToCompile, new CompilationResult(graphToCompile.compilationId()), id, options);
printer.finish(compResult);
try (DebugContext.Scope s = debug.scope("CodeInstall", getCodeCache(), installedCodeOwner, compResult);
@@ -1019,17 +1019,19 @@
*/
protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph) {
OptionValues options = graph == null ? getInitialOptions() : graph.getOptions();
- return compile(installedCodeOwner, graph, new CompilationResult(), getOrCreateCompilationId(installedCodeOwner, graph), options);
+ CompilationIdentifier compilationId = getOrCreateCompilationId(installedCodeOwner, graph);
+ return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
}
protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, CompilationIdentifier compilationId) {
OptionValues options = graph == null ? getInitialOptions() : graph.getOptions();
- return compile(installedCodeOwner, graph, new CompilationResult(), compilationId, options);
+ return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
}
protected final CompilationResult compile(ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, OptionValues options) {
assert graph == null || graph.getOptions() == options;
- return compile(installedCodeOwner, graph, new CompilationResult(), getOrCreateCompilationId(installedCodeOwner, graph), options);
+ CompilationIdentifier compilationId = getOrCreateCompilationId(installedCodeOwner, graph);
+ return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
}
/**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java Sun Sep 03 14:19:45 2017 +0200
@@ -64,7 +64,7 @@
final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
final StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(),
- createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default);
+ createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
for (Infopoint sp : cr.getInfopoints()) {
assertNotNull(sp.reason);
if (sp instanceof Call) {
@@ -86,7 +86,7 @@
assertTrue(graphLineSPs > 0);
PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true));
final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), graphBuilderSuite, OptimisticOptimizations.ALL, graph.getProfilingInfo(),
- createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default);
+ createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
int lineSPs = 0;
for (Infopoint sp : cr.getInfopoints()) {
assertNotNull(sp.reason);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java Sun Sep 03 14:19:45 2017 +0200
@@ -123,7 +123,7 @@
ProfilingInfo profilingInfo = graph.getProfilingInfo(method);
/* The default class and configuration for compilation results. */
- CompilationResult compilationResult = new CompilationResult();
+ CompilationResult compilationResult = new CompilationResult(graph.compilationId());
CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default;
/* Invoke the whole Graal compilation pipeline. */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/NodeBitMapTest.java Sun Sep 03 14:19:45 2017 +0200
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.graph.test;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeBitMap;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.options.OptionValues;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NodeBitMapTest extends GraphTest {
+
+ @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
+ static final class TestNode extends Node {
+ public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
+
+ protected TestNode() {
+ super(TYPE);
+ }
+ }
+
+ private Graph graph;
+ private TestNode[] nodes = new TestNode[100];
+ private NodeBitMap map;
+
+ @Before
+ public void before() {
+ // Need to initialize HotSpotGraalRuntime before any Node class is initialized.
+ Graal.getRuntime();
+
+ OptionValues options = getOptions();
+ graph = new Graph(options, getDebug(options));
+ for (int i = 0; i < nodes.length; i++) {
+ nodes[i] = graph.add(new TestNode());
+ }
+ map = graph.createNodeBitMap();
+ }
+
+ @Test
+ public void iterateEmpty() {
+ for (Node n : map) {
+ Assert.fail("no elements expected: " + n);
+ }
+ }
+
+ @Test
+ public void iterateMarkedNodes() {
+ map.mark(nodes[99]);
+ map.mark(nodes[0]);
+ map.mark(nodes[7]);
+ map.mark(nodes[1]);
+ map.mark(nodes[53]);
+
+ Iterator<Node> iter = map.iterator();
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[0], iter.next());
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[1], iter.next());
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[7], iter.next());
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[53], iter.next());
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[99], iter.next());
+ Assert.assertFalse(iter.hasNext());
+ }
+
+ @Test
+ public void deleteNodeWhileIterating() {
+ map.mark(nodes[99]);
+ map.mark(nodes[0]);
+ map.mark(nodes[7]);
+ map.mark(nodes[1]);
+ map.mark(nodes[53]);
+
+ Iterator<Node> iter = map.iterator();
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[0], iter.next());
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[1], iter.next());
+ nodes[7].markDeleted();
+ nodes[53].markDeleted();
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[99], iter.next());
+ Assert.assertFalse(iter.hasNext());
+ }
+
+ @Test
+ public void deleteAllNodesBeforeIterating() {
+ for (int i = 0; i < nodes.length; i++) {
+ map.mark(nodes[i]);
+ nodes[i].markDeleted();
+ }
+
+ Iterator<Node> iter = map.iterator();
+ Assert.assertFalse(iter.hasNext());
+ }
+
+ @Test
+ public void multipleHasNextInvocations() {
+ map.mark(nodes[7]);
+
+ Iterator<Node> iter = map.iterator();
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[7], iter.next());
+ Assert.assertFalse(iter.hasNext());
+ }
+
+ @Test(expected = NoSuchElementException.class)
+ public void noSuchElement() {
+ map.iterator().next();
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void concurrentModification() {
+ map.mark(nodes[7]);
+
+ map.mark(nodes[99]);
+ map.mark(nodes[0]);
+ map.mark(nodes[7]);
+ map.mark(nodes[1]);
+ map.mark(nodes[53]);
+
+ Iterator<Node> iter = map.iterator();
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[0], iter.next());
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[1], iter.next());
+ Assert.assertTrue(iter.hasNext());
+ nodes[7].markDeleted();
+ iter.next();
+ }
+
+ @Test
+ public void nextWithoutHasNext() {
+ map.mark(nodes[99]);
+ map.mark(nodes[0]);
+ map.mark(nodes[7]);
+ map.mark(nodes[1]);
+ map.mark(nodes[53]);
+
+ Iterator<Node> iter = map.iterator();
+ Assert.assertEquals(nodes[0], iter.next());
+ Assert.assertEquals(nodes[1], iter.next());
+ Assert.assertEquals(nodes[7], iter.next());
+ Assert.assertEquals(nodes[53], iter.next());
+ Assert.assertEquals(nodes[99], iter.next());
+ Assert.assertFalse(iter.hasNext());
+ }
+
+ @Test
+ public void markWhileIterating() {
+ map.mark(nodes[0]);
+
+ Iterator<Node> iter = map.iterator();
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[0], iter.next());
+ map.mark(nodes[7]);
+ Assert.assertTrue(iter.hasNext());
+ map.mark(nodes[1]);
+ Assert.assertEquals(nodes[7], iter.next());
+ map.mark(nodes[99]);
+ map.mark(nodes[53]);
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[53], iter.next());
+ Assert.assertTrue(iter.hasNext());
+ Assert.assertEquals(nodes[99], iter.next());
+ Assert.assertFalse(iter.hasNext());
+ }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java Sun Sep 03 14:19:45 2017 +0200
@@ -23,22 +23,23 @@
package org.graalvm.compiler.graph;
import java.util.Arrays;
+import java.util.ConcurrentModificationException;
import java.util.Iterator;
+import java.util.NoSuchElementException;
import org.graalvm.compiler.graph.iterators.NodeIterable;
-public final class NodeBitMap implements NodeIterable<Node> {
+public final class NodeBitMap extends NodeIdAccessor implements NodeIterable<Node> {
private static final int SHIFT = 6;
private long[] bits;
private int nodeCount;
private int counter;
- private final Graph graph;
public NodeBitMap(Graph graph) {
+ super(graph);
this.nodeCount = graph.nodeIdCount();
this.bits = new long[sizeForNodeCount(nodeCount)];
- this.graph = graph;
}
private static int sizeForNodeCount(int nodeCount) {
@@ -50,9 +51,9 @@
}
private NodeBitMap(NodeBitMap other) {
+ super(other.graph);
this.bits = other.bits.clone();
this.nodeCount = other.nodeCount;
- this.graph = other.graph;
}
public Graph graph() {
@@ -60,12 +61,12 @@
}
public boolean isNew(Node node) {
- return node.id() >= nodeCount;
+ return getNodeId(node) >= nodeCount;
}
public boolean isMarked(Node node) {
assert check(node, false);
- return isMarked(node.id());
+ return isMarked(getNodeId(node));
}
public boolean checkAndMarkInc(Node node) {
@@ -84,33 +85,33 @@
public boolean isMarkedAndGrow(Node node) {
assert check(node, true);
- int id = node.id();
+ int id = getNodeId(node);
checkGrow(id);
return isMarked(id);
}
public void mark(Node node) {
assert check(node, false);
- int id = node.id();
+ int id = getNodeId(node);
bits[id >> SHIFT] |= (1L << id);
}
public void markAndGrow(Node node) {
assert check(node, true);
- int id = node.id();
+ int id = getNodeId(node);
checkGrow(id);
bits[id >> SHIFT] |= (1L << id);
}
public void clear(Node node) {
assert check(node, false);
- int id = node.id();
+ int id = getNodeId(node);
bits[id >> SHIFT] &= ~(1L << id);
}
public void clearAndGrow(Node node) {
assert check(node, true);
- int id = node.id();
+ int id = getNodeId(node);
checkGrow(id);
bits[id >> SHIFT] &= ~(1L << id);
}
@@ -181,15 +182,30 @@
}
}
- protected int nextMarkedNodeId(int fromNodeId) {
+ protected Node nextMarkedNode(int fromNodeId) {
assert fromNodeId >= 0;
int wordIndex = fromNodeId >> SHIFT;
int wordsInUse = bits.length;
if (wordIndex < wordsInUse) {
- long word = bits[wordIndex] & (0xFFFFFFFFFFFFFFFFL << fromNodeId);
+ long word = getPartOfWord(bits[wordIndex], fromNodeId);
while (true) {
- if (word != 0) {
- return wordIndex * Long.SIZE + Long.numberOfTrailingZeros(word);
+ while (word != 0) {
+ int bitIndex = Long.numberOfTrailingZeros(word);
+ int nodeId = wordIndex * Long.SIZE + bitIndex;
+ Node result = graph.getNode(nodeId);
+ if (result == null) {
+ // node was deleted -> clear the bit and continue searching
+ bits[wordIndex] = bits[wordIndex] & ~(1 << bitIndex);
+ int nextNodeId = nodeId + 1;
+ if ((nextNodeId & (Long.SIZE - 1)) == 0) {
+ // we reached the end of this word
+ break;
+ } else {
+ word = getPartOfWord(word, nextNodeId);
+ }
+ } else {
+ return result;
+ }
}
if (++wordIndex == wordsInUse) {
break;
@@ -197,30 +213,56 @@
word = bits[wordIndex];
}
}
- return -2;
+ return null;
+ }
+
+ private static long getPartOfWord(long word, int firstNodeIdToInclude) {
+ return word & (0xFFFFFFFFFFFFFFFFL << firstNodeIdToInclude);
}
+ /**
+ * This iterator only returns nodes that are marked in the {@link NodeBitMap} and are alive in
+ * the corresponding {@link Graph}.
+ */
private class MarkedNodeIterator implements Iterator<Node> {
- private int nextNodeId;
+ private int currentNodeId;
+ private Node currentNode;
MarkedNodeIterator() {
- nextNodeId = -1;
+ currentNodeId = -1;
forward();
}
private void forward() {
- nextNodeId = NodeBitMap.this.nextMarkedNodeId(nextNodeId + 1);
+ assert currentNode == null;
+ currentNode = NodeBitMap.this.nextMarkedNode(currentNodeId + 1);
+ if (currentNode != null) {
+ assert currentNode.isAlive();
+ currentNodeId = getNodeId(currentNode);
+ } else {
+ currentNodeId = -1;
+ }
}
@Override
public boolean hasNext() {
- return nextNodeId >= 0;
+ if (currentNode == null && currentNodeId >= 0) {
+ forward();
+ }
+ return currentNodeId >= 0;
}
@Override
public Node next() {
- Node result = graph.getNode(nextNodeId);
- forward();
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ if (!currentNode.isAlive()) {
+ throw new ConcurrentModificationException("NodeBitMap was modified between the calls to hasNext() and next()");
+ }
+
+ Node result = currentNode;
+ currentNode = null;
return result;
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64RawNativeCallNode.java Fri Sep 01 14:13:09 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.hotspot.aarch64;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
-
-import org.graalvm.compiler.core.aarch64.AArch64NodeLIRBuilder;
-import org.graalvm.compiler.core.common.type.RawPointerStamp;
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.graph.NodeInputList;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.spi.LIRLowerable;
-import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-
-import jdk.vm.ci.code.CallingConvention;
-import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Value;
-
-@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = SIZE_UNKNOWN)
-public final class AArch64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
- public static final NodeClass<AArch64RawNativeCallNode> TYPE = NodeClass.create(AArch64RawNativeCallNode.class);
-
- protected final JavaConstant functionPointer;
- @Input NodeInputList<ValueNode> args;
-
- public AArch64RawNativeCallNode(JavaKind returnType, JavaConstant functionPointer, ValueNode[] args) {
- super(TYPE, StampFactory.forKind(returnType));
- this.functionPointer = functionPointer;
- this.args = new NodeInputList<>(this, args);
- }
-
- private static class PointerType implements JavaType {
-
- @Override
- public String getName() {
- return "void*";
- }
-
- @Override
- public JavaType getComponentType() {
- return null;
- }
-
- @Override
- public JavaType getArrayClass() {
- return null;
- }
-
- @Override
- public JavaKind getJavaKind() {
- // native pointers and java objects use the same registers in the calling convention
- return JavaKind.Object;
- }
-
- @Override
- public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
- return null;
- }
- }
-
- private static JavaType toJavaType(Stamp stamp, MetaAccessProvider metaAccess) {
- if (stamp instanceof RawPointerStamp) {
- return new PointerType();
- } else {
- return stamp.javaType(metaAccess);
- }
- }
-
- @Override
- public void generate(NodeLIRBuilderTool generator) {
- AArch64NodeLIRBuilder gen = (AArch64NodeLIRBuilder) generator;
- Value[] parameter = new Value[args.count()];
- JavaType[] parameterTypes = new JavaType[args.count()];
- for (int i = 0; i < args.count(); i++) {
- parameter[i] = generator.operand(args.get(i));
- parameterTypes[i] = toJavaType(args.get(i).stamp(), gen.getLIRGeneratorTool().getMetaAccess());
- }
- JavaType returnType = toJavaType(stamp(), gen.getLIRGeneratorTool().getMetaAccess());
- CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.NativeCall, returnType, parameterTypes,
- generator.getLIRGeneratorTool());
- gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter);
- if (this.getStackKind() != JavaKind.Void) {
- generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
- }
- }
-
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64RawNativeCallNode.java Fri Sep 01 14:13:09 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.hotspot.amd64;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-
-import org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder;
-import org.graalvm.compiler.core.common.type.RawPointerStamp;
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.graph.NodeInputList;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodeinfo.NodeSize;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.spi.LIRLowerable;
-import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-
-import jdk.vm.ci.code.CallingConvention;
-import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.JavaType;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Value;
-
-@NodeInfo(cycles = CYCLES_UNKNOWN, cyclesRationale = "Native call is a block hole", size = NodeSize.SIZE_UNKNOWN)
-public final class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
- public static final NodeClass<AMD64RawNativeCallNode> TYPE = NodeClass.create(AMD64RawNativeCallNode.class);
-
- protected final JavaConstant functionPointer;
- @Input NodeInputList<ValueNode> args;
-
- public AMD64RawNativeCallNode(JavaKind returnType, JavaConstant functionPointer, ValueNode[] args) {
- super(TYPE, StampFactory.forKind(returnType));
- this.functionPointer = functionPointer;
- this.args = new NodeInputList<>(this, args);
- }
-
- private static class PointerType implements JavaType {
-
- @Override
- public String getName() {
- return "void*";
- }
-
- @Override
- public JavaType getComponentType() {
- return null;
- }
-
- @Override
- public JavaType getArrayClass() {
- return null;
- }
-
- @Override
- public JavaKind getJavaKind() {
- // native pointers and java objects use the same registers in the calling convention
- return JavaKind.Object;
- }
-
- @Override
- public ResolvedJavaType resolve(ResolvedJavaType accessingClass) {
- return null;
- }
- }
-
- private static JavaType toJavaType(Stamp stamp, MetaAccessProvider metaAccess) {
- if (stamp instanceof RawPointerStamp) {
- return new PointerType();
- } else {
- return stamp.javaType(metaAccess);
- }
- }
-
- @Override
- public void generate(NodeLIRBuilderTool generator) {
- AMD64NodeLIRBuilder gen = (AMD64NodeLIRBuilder) generator;
- Value[] parameter = new Value[args.count()];
- JavaType[] parameterTypes = new JavaType[args.count()];
- for (int i = 0; i < args.count(); i++) {
- parameter[i] = generator.operand(args.get(i));
- parameterTypes[i] = toJavaType(args.get(i).stamp(), gen.getLIRGeneratorTool().getMetaAccess());
- }
- JavaType returnType = toJavaType(stamp(), gen.getLIRGeneratorTool().getMetaAccess());
- CallingConvention cc = generator.getLIRGeneratorTool().getCodeCache().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.NativeCall, returnType, parameterTypes,
- generator.getLIRGeneratorTool());
- gen.getLIRGeneratorTool().emitCCall(functionPointer.asLong(), cc, parameter, countFloatingTypeArguments(args));
- if (this.getStackKind() != JavaKind.Void) {
- generator.setResult(this, gen.getLIRGeneratorTool().emitMove(cc.getReturn()));
- }
- }
-
- private static int countFloatingTypeArguments(NodeInputList<ValueNode> args) {
- int count = 0;
- for (ValueNode n : args) {
- if (n.getStackKind() == JavaKind.Double || n.getStackKind() == JavaKind.Float) {
- count++;
- }
- }
- if (count > 8) {
- return 8;
- }
- return count;
- }
-
-}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java Sun Sep 03 14:19:45 2017 +0200
@@ -207,7 +207,6 @@
"oracle/jrockit/jfr/Timing.counterTime()J",
"oracle/jrockit/jfr/VMJFR.classID0(Ljava/lang/Class;)J",
"oracle/jrockit/jfr/VMJFR.threadID()I",
- "sun/misc/Unsafe.copyMemory(Ljava/lang/Object;JLjava/lang/Object;JJ)V",
"sun/nio/cs/ISO_8859_1$Encoder.encodeISOArray([CI[BII)I",
"sun/security/provider/DigestBase.implCompressMultiBlock([BII)I",
"sun/security/provider/SHA.implCompress([BI)V",
@@ -273,7 +272,6 @@
"jdk/internal/misc/Unsafe.compareAndExchangeShortRelease(Ljava/lang/Object;JSS)S",
"jdk/internal/misc/Unsafe.compareAndSetByte(Ljava/lang/Object;JBB)Z",
"jdk/internal/misc/Unsafe.compareAndSetShort(Ljava/lang/Object;JSS)Z",
- "jdk/internal/misc/Unsafe.copyMemory0(Ljava/lang/Object;JLjava/lang/Object;JJ)V",
"jdk/internal/misc/Unsafe.getAndAddByte(Ljava/lang/Object;JB)B",
"jdk/internal/misc/Unsafe.getAndAddShort(Ljava/lang/Object;JS)S",
"jdk/internal/misc/Unsafe.getAndSetByte(Ljava/lang/Object;JB)B",
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotUnsafeSubstitutionTest.java Sun Sep 03 14:19:45 2017 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import org.graalvm.compiler.replacements.test.MethodSubstitutionTest;
+import org.junit.Test;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
+
+/**
+ * Tests the VM independent intrinsification of {@link Unsafe} methods.
+ */
+public class HotSpotUnsafeSubstitutionTest extends MethodSubstitutionTest {
+
+ public void testSubstitution(String testMethodName, Class<?> holder, String methodName, Class<?>[] parameterTypes, Object receiver, Object[] args1, Object[] args2) {
+ ResolvedJavaMethod testMethod = getResolvedJavaMethod(testMethodName);
+ ResolvedJavaMethod originalMethod = getResolvedJavaMethod(holder, methodName, parameterTypes);
+
+ // Force compilation
+ InstalledCode code = getCode(testMethod);
+ assert code != null;
+
+ // Verify that the original method and the substitution produce the same value
+ Object expected = invokeSafe(originalMethod, receiver, args1);
+ Object actual = invokeSafe(testMethod, null, args2);
+ assertDeepEquals(expected, actual);
+
+ // Verify that the generated code and the original produce the same value
+ expected = invokeSafe(originalMethod, receiver, args1);
+ actual = executeVarargsSafe(code, args2);
+ assertDeepEquals(expected, actual);
+
+ }
+
+ @Test
+ public void testUnsafeSubstitutions() throws Exception {
+ testGraph("unsafeCopyMemory");
+ }
+
+ public void unsafeCopyMemory(Object srcBase, long srcOffset, Object dstBase, long dstOffset, long bytes) {
+ UNSAFE.copyMemory(srcBase, srcOffset, dstBase, dstOffset, bytes);
+ }
+
+ public byte[] testCopyMemorySnippet(long src, int bytes) {
+ byte[] result = new byte[bytes];
+ UNSAFE.copyMemory(null, src, result, Unsafe.ARRAY_BYTE_BASE_OFFSET, bytes);
+ return result;
+ }
+
+ @Test
+ public void testCopyMemory() {
+ int size = 128;
+ long src = UNSAFE.allocateMemory(size);
+ for (int i = 0; i < size; i++) {
+ UNSAFE.putByte(null, src + i, (byte) i);
+ }
+ test("testCopyMemorySnippet", src, size);
+ }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java Sun Sep 03 14:19:45 2017 +0200
@@ -64,9 +64,9 @@
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.tiers.SuitesProvider;
import org.graalvm.compiler.word.Word;
-import org.graalvm.util.Equivalence;
import org.graalvm.util.EconomicMap;
import org.graalvm.util.EconomicSet;
+import org.graalvm.util.Equivalence;
import org.graalvm.util.MapCursor;
import org.graalvm.word.Pointer;
@@ -258,6 +258,18 @@
private static native void sha5ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state);
/**
+ * @see org.graalvm.compiler.hotspot.meta.HotSpotUnsafeSubstitutions#copyMemory
+ */
+ public static final ForeignCallDescriptor UNSAFE_ARRAYCOPY = new ForeignCallDescriptor("unsafe_arraycopy", void.class, Word.class, Word.class, Word.class);
+
+ public static void unsafeArraycopy(Word srcAddr, Word dstAddr, Word size) {
+ unsafeArraycopyStub(HotSpotBackend.UNSAFE_ARRAYCOPY, srcAddr, dstAddr, size);
+ }
+
+ @NodeIntrinsic(ForeignCallNode.class)
+ private static native void unsafeArraycopyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word srcAddr, Word dstAddr, Word size);
+
+ /**
* @see VMErrorNode
*/
public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class);
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java Sun Sep 03 14:19:45 2017 +0200
@@ -198,7 +198,7 @@
public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) {
StructuredGraph graph = createGraph(method, entryBCI, useProfilingInfo, compilationId, options, debug);
- CompilationResult result = new CompilationResult();
+ CompilationResult result = new CompilationResult(compilationId);
return compileHelper(CompilationResultBuilderFactory.Default, result, graph, method, entryBCI, useProfilingInfo, options);
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java Sun Sep 03 14:19:45 2017 +0200
@@ -111,6 +111,7 @@
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
/**
* Defines the {@link Plugins} used when running on HotSpot.
@@ -202,6 +203,7 @@
registerCRC32Plugins(invocationPlugins, config, replacementBytecodeProvider);
registerBigIntegerPlugins(invocationPlugins, config, replacementBytecodeProvider);
registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
+ registerUnsafePlugins(invocationPlugins, replacementBytecodeProvider);
StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true);
for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
@@ -313,6 +315,17 @@
r.registerMethodSubstitution(ReflectionSubstitutions.class, "getClassAccessFlags", Class.class);
}
+ private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementBytecodeProvider) {
+ Registration r;
+ if (Java8OrEarlier) {
+ r = new Registration(plugins, Unsafe.class, replacementBytecodeProvider);
+ } else {
+ r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementBytecodeProvider);
+ }
+ r.registerMethodSubstitution(HotSpotUnsafeSubstitutions.class, HotSpotUnsafeSubstitutions.copyMemoryName, "copyMemory", Receiver.class, Object.class, long.class, Object.class, long.class,
+ long.class);
+ }
+
private static final LocationIdentity INSTANCE_KLASS_CONSTANTS = NamedLocationIdentity.immutable("InstanceKlass::_constants");
private static final LocationIdentity CONSTANT_POOL_LENGTH = NamedLocationIdentity.immutable("ConstantPool::_length");
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java Sun Sep 03 14:19:45 2017 +0200
@@ -51,6 +51,7 @@
import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA5_IMPL_COMPRESS;
import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA_IMPL_COMPRESS;
import static org.graalvm.compiler.hotspot.HotSpotBackend.SQUARE_TO_LEN;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.UNSAFE_ARRAYCOPY;
import static org.graalvm.compiler.hotspot.HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER;
import static org.graalvm.compiler.hotspot.HotSpotBackend.VM_ERROR;
import static org.graalvm.compiler.hotspot.HotSpotBackend.WRONG_METHOD_HANDLER;
@@ -330,6 +331,8 @@
registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit);
registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy);
+ registerForeignCall(UNSAFE_ARRAYCOPY, c.unsafeArraycopy, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
+
if (c.useMultiplyToLenIntrinsic()) {
registerForeignCall(MULTIPLY_TO_LEN, c.multiplyToLen, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.getArrayLocation(JavaKind.Int));
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotUnsafeSubstitutions.java Sun Sep 03 14:19:45 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.meta;
+
+import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
+
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.nodes.ComputeObjectAddressNode;
+import org.graalvm.compiler.word.Word;
+import org.graalvm.word.WordFactory;
+
+@ClassSubstitution(className = {"jdk.internal.misc.Unsafe", "sun.misc.Unsafe"})
+public class HotSpotUnsafeSubstitutions {
+
+ public static final String copyMemoryName = Java8OrEarlier ? "copyMemory" : "copyMemory0";
+
+ @SuppressWarnings("unused")
+ @MethodSubstitution(isStatic = false)
+ static void copyMemory(Object receiver, Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) {
+ Word srcAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(srcBase, srcOffset));
+ Word dstAddr = WordFactory.unsigned(ComputeObjectAddressNode.get(destBase, destOffset));
+ Word size = Word.signed(bytes);
+ HotSpotBackend.unsafeArraycopy(srcAddr, dstAddr, size);
+ }
+}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java Sun Sep 03 14:19:45 2017 +0200
@@ -216,8 +216,9 @@
@SuppressWarnings("try")
private CompilationResult buildCompilationResult(DebugContext debug, final Backend backend) {
- CompilationResult compResult = new CompilationResult(toString(), GeneratePIC.getValue(options));
- final StructuredGraph graph = getGraph(debug, getStubCompilationId());
+ CompilationIdentifier compilationId = getStubCompilationId();
+ final StructuredGraph graph = getGraph(debug, compilationId);
+ CompilationResult compResult = new CompilationResult(compilationId, toString(), GeneratePIC.getValue(options));
// Stubs cannot be recompiled so they cannot be compiled with assumptions
assert graph.getAssumptions() == null;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceInterval.java Sun Sep 03 14:19:45 2017 +0200
@@ -365,10 +365,6 @@
return intTo;
}
- int numUsePositions() {
- return numUsePos();
- }
-
public void setLocationHint(IntervalHint interval) {
locationHint = interval;
}
@@ -452,6 +448,10 @@
return spillSt == SpillState.StartInMemory || (spillSt == SpillState.SpillStore && opId > spillDefinitionPos() && !canMaterialize());
}
+ public boolean preSpilledAllocated() {
+ return spillState() == SpillState.StartInMemory && numUsePos() == 0 && !hasHint();
+ }
+
// test intersection
boolean intersects(TraceInterval i) {
return intersectsAt(i) != -1;
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanLifetimeAnalysisPhase.java Sun Sep 03 14:19:45 2017 +0200
@@ -541,16 +541,23 @@
assert instructionIndex == 0 : "not at start?" + instructionIndex;
handleTraceBegin(blocks[0]);
- // fix spill state for phi/incoming intervals
- for (TraceInterval interval : allocator.intervals()) {
- if (interval != null && interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
- // there was a definition in a phi/incoming
- interval.setSpillState(SpillState.NoSpillStore);
- }
- }
if (TraceRAuseInterTraceHints.getValue(allocator.getLIR().getOptions())) {
addInterTraceHints();
}
+ // fix spill state for phi/incoming intervals
+ for (TraceInterval interval : allocator.intervals()) {
+ if (interval != null) {
+ if (interval.spillState().equals(SpillState.NoDefinitionFound) && interval.spillDefinitionPos() != -1) {
+ // there was a definition in a phi/incoming
+ interval.setSpillState(SpillState.NoSpillStore);
+ }
+ if (interval.preSpilledAllocated()) {
+ // pre-spill unused, start in memory intervals
+ allocator.assignSpillSlot(interval);
+ }
+ }
+ }
+
for (FixedInterval interval1 : allocator.fixedIntervals()) {
if (interval1 != null) {
/* We use [-1, 0] to avoid intersection with incoming values. */
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java Sun Sep 03 14:19:45 2017 +0200
@@ -153,7 +153,7 @@
@Override
public boolean apply(TraceInterval i) {
// all TraceIntervals are variable intervals
- return true;
+ return !i.preSpilledAllocated();
}
};
private static final Comparator<TraceInterval> SORT_BY_FROM_COMP = new Comparator<TraceInterval>() {
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java Sun Sep 03 14:19:45 2017 +0200
@@ -319,7 +319,7 @@
assert !graph.isFrozen();
ResolvedJavaMethod installedCodeOwner = graph.method();
request = new Request<>(graph, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
- graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(), CompilationResultBuilderFactory.Default);
+ graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
}
/**
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java Sun Sep 03 14:19:45 2017 +0200
@@ -209,7 +209,6 @@
int nodeCount = nodeOrder.nextOrderId;
assert nodeOrder.orderIds.get(graph.start()) == START_NODE_ORDER_ID;
assert nodeOrder.orderIds.get(graph.start().next()) == FIRST_NODE_ORDER_ID;
- assert nodeCount == graph.getNodeCount() + 1;
long[] nodeStartOffsets = new long[nodeCount];
UnmodifiableMapCursor<Node, Integer> cursor = nodeOrder.orderIds.getEntries();
@@ -218,6 +217,7 @@
Integer orderId = cursor.getValue();
assert !(node instanceof AbstractBeginNode) || nodeOrder.orderIds.get(((AbstractBeginNode) node).next()) == orderId + BEGIN_NEXT_ORDER_ID_OFFSET;
+ assert nodeStartOffsets[orderId] == 0;
nodeStartOffsets[orderId] = writer.getBytesWritten();
/* Write out the type, properties, and edges. */
@@ -284,7 +284,6 @@
writer.putUV(nodeOrder.maxFixedNodeOrderId);
writer.putUV(nodeCount);
for (int i = 0; i < nodeCount; i++) {
- assert i == NULL_ORDER_ID || i == START_NODE_ORDER_ID || nodeStartOffsets[i] > 0;
writer.putUV(metadataStart - nodeStartOffsets[i]);
}
@@ -344,8 +343,25 @@
} while (current != null);
maxFixedNodeOrderId = nextOrderId - 1;
+
+ /*
+ * Emit all parameters consecutively at a known location (after all fixed nodes). This
+ * allows substituting parameters when inlining during decoding by pre-initializing the
+ * decoded node list.
+ *
+ * Note that not all parameters must be present (unused parameters are deleted after
+ * parsing). This leads to holes in the orderId, i.e., unused orderIds.
+ */
+ int parameterCount = graph.method().getSignature().getParameterCount(!graph.method().isStatic());
+ for (ParameterNode node : graph.getNodes(ParameterNode.TYPE)) {
+ assert orderIds.get(node) == null : "Parameter node must not be ordered yet";
+ assert node.index() < parameterCount : "Parameter index out of range";
+ orderIds.set(node, nextOrderId + node.index());
+ }
+ nextOrderId += parameterCount;
+
for (Node node : graph.getNodes()) {
- assert (node instanceof FixedNode) == (orderIds.get(node) != null) : "all fixed nodes must be ordered: " + node;
+ assert (node instanceof FixedNode || node instanceof ParameterNode) == (orderIds.get(node) != null) : "all fixed nodes and ParameterNodes must be ordered: " + node;
add(node);
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java Sun Sep 03 14:19:45 2017 +0200
@@ -37,6 +37,7 @@
import org.graalvm.compiler.bytecode.BytecodeDisassembler;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.code.DisassemblerProvider;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.core.common.alloc.Trace;
import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@@ -72,6 +73,7 @@
private CFGPrinter cfgPrinter;
private File cfgFile;
private JavaMethod curMethod;
+ private CompilationIdentifier curCompilation;
private List<String> curDecorators = Collections.emptyList();
@Override
@@ -92,6 +94,7 @@
*/
private boolean checkMethodScope(DebugContext debug) {
JavaMethod method = null;
+ CompilationIdentifier compilation = null;
ArrayList<String> decorators = new ArrayList<>();
for (Object o : debug.context()) {
if (o instanceof JavaMethod) {
@@ -102,22 +105,33 @@
if (graph.method() != null) {
method = graph.method();
decorators.clear();
+ compilation = graph.compilationId();
}
} else if (o instanceof DebugDumpScope) {
DebugDumpScope debugDumpScope = (DebugDumpScope) o;
if (debugDumpScope.decorator) {
decorators.add(debugDumpScope.name);
}
+ } else if (o instanceof CompilationResult) {
+ CompilationResult compilationResult = (CompilationResult) o;
+ compilation = compilationResult.getCompilationId();
}
}
- if (method == null) {
+ if (method == null && compilation == null) {
return false;
}
- if (!method.equals(curMethod) || !curDecorators.equals(decorators)) {
- cfgPrinter.printCompilation(method);
+ if (compilation != null) {
+ if (!compilation.equals(curCompilation) || !curDecorators.equals(decorators)) {
+ cfgPrinter.printCompilation(compilation);
+ }
+ } else {
+ if (!method.equals(curMethod) || !curDecorators.equals(decorators)) {
+ cfgPrinter.printCompilation(method);
+ }
}
+ curCompilation = compilation;
curMethod = method;
curDecorators = decorators;
return true;
@@ -277,6 +291,7 @@
cfgPrinter = null;
curDecorators = Collections.emptyList();
curMethod = null;
+ curCompilation = null;
}
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CompilationPrinter.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CompilationPrinter.java Sun Sep 03 14:19:45 2017 +0200
@@ -31,6 +31,7 @@
import java.util.List;
import java.util.Map;
+import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.debug.LogStream;
import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.lir.util.IndexedValueMap;
@@ -115,12 +116,25 @@
/**
* Prints a compilation timestamp for a given method.
*
- * @param method the method for which a timestamp will be printed
+ * @param javaMethod the method for which a timestamp will be printed
*/
- public void printCompilation(JavaMethod method) {
+ public void printCompilation(JavaMethod javaMethod) {
+ printCompilation(javaMethod.format("%H::%n"), javaMethod.format("%f %r %H.%n(%p)"));
+ }
+
+ /**
+ * Prints a compilation id.
+ *
+ * @param compilationId the compilation method for which an id will be printed
+ */
+ public void printCompilation(CompilationIdentifier compilationId) {
+ printCompilation(compilationId.toString(CompilationIdentifier.Verbosity.DETAILED), compilationId.toString(CompilationIdentifier.Verbosity.DETAILED));
+ }
+
+ private void printCompilation(final String name, String method) {
begin("compilation");
- out.print("name \" ").print(method.format("%H::%n")).println('"');
- out.print("method \"").print(method.format("%f %r %H.%n(%p)")).println('"');
+ out.print("name \" ").print(name).println('"');
+ out.print("method \"").print(method).println('"');
out.print("date ").println(System.currentTimeMillis());
end("compilation");
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/ClassSubstitutionVerifier.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/ClassSubstitutionVerifier.java Sun Sep 03 14:19:45 2017 +0200
@@ -95,10 +95,13 @@
TypeElement typeElement = null;
for (String className : classNames) {
typeElement = env.getElementUtils().getTypeElement(className);
- if (typeElement == null && !optional) {
- env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
+ if (typeElement != null) {
+ break;
}
}
+ if (typeElement == null && !optional) {
+ env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
+ }
return typeElement;
}
--- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java Sun Sep 03 14:19:45 2017 +0200
@@ -707,10 +707,22 @@
}
}
+ LoopScope inlineLoopScope = createInitialLoopScope(inlineScope, predecessor);
+
+ /*
+ * The GraphEncoder assigns parameters a nodeId immediately after the fixed nodes.
+ * Initializing createdNodes here avoid decoding and immediately replacing the
+ * ParameterNodes.
+ */
+ int firstArgumentNodeId = inlineScope.maxFixedNodeOrderId + 1;
+ for (int i = 0; i < arguments.length; i++) {
+ inlineLoopScope.createdNodes[firstArgumentNodeId + i] = arguments[i];
+ }
+
/*
* Do the actual inlining by returning the initial loop scope for the inlined method scope.
*/
- return createInitialLoopScope(inlineScope, predecessor);
+ return inlineLoopScope;
}
@Override
@@ -1028,9 +1040,7 @@
if (node instanceof ParameterNode) {
ParameterNode param = (ParameterNode) node;
if (methodScope.isInlinedMethod()) {
- Node result = methodScope.arguments[param.index()];
- assert result != null;
- return result;
+ throw GraalError.shouldNotReachHere("Parameter nodes are already registered when the inlined scope is created");
} else if (parameterPlugin != null) {
assert !methodScope.isInlinedMethod();
--- a/hotspot/src/os/aix/vm/os_aix.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os/aix/vm/os_aix.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1185,62 +1185,6 @@
// directory not the java application's temp directory, ala java.io.tmpdir.
const char* os::get_temp_directory() { return "/tmp"; }
-static bool file_exists(const char* filename) {
- struct stat statbuf;
- if (filename == NULL || strlen(filename) == 0) {
- return false;
- }
- return os::stat(filename, &statbuf) == 0;
-}
-
-bool os::dll_build_name(char* buffer, size_t buflen,
- const char* pname, const char* fname) {
- bool retval = false;
- // Copied from libhpi
- const size_t pnamelen = pname ? strlen(pname) : 0;
-
- // Return error on buffer overflow.
- if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
- *buffer = '\0';
- return retval;
- }
-
- if (pnamelen == 0) {
- snprintf(buffer, buflen, "lib%s.so", fname);
- retval = true;
- } else if (strchr(pname, *os::path_separator()) != NULL) {
- int n;
- char** pelements = split_path(pname, &n);
- if (pelements == NULL) {
- return false;
- }
- for (int i = 0; i < n; i++) {
- // Really shouldn't be NULL, but check can't hurt
- if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
- continue; // skip the empty path values
- }
- snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
- if (file_exists(buffer)) {
- retval = true;
- break;
- }
- }
- // release the storage
- for (int i = 0; i < n; i++) {
- if (pelements[i] != NULL) {
- FREE_C_HEAP_ARRAY(char, pelements[i]);
- }
- }
- if (pelements != NULL) {
- FREE_C_HEAP_ARRAY(char*, pelements);
- }
- } else {
- snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
- retval = true;
- }
- return retval;
-}
-
// Check if addr is inside libjvm.so.
bool os::address_is_in_vm(address addr) {
@@ -1493,12 +1437,7 @@
}
void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
- st->print("CPU:");
- st->print("total %d", os::processor_count());
- // It's not safe to query number of active processors after crash.
- // st->print("(active %d)", os::active_processor_count());
- st->print(" %s", VM_Version::features());
- st->cr();
+ // Nothing to do beyond what os::print_cpu_info() does.
}
static void print_signal_handler(outputStream* st, int sig,
@@ -2668,11 +2607,10 @@
////////////////////////////////////////////////////////////////////////////////
// suspend/resume support
-// the low-level signal-based suspend/resume support is a remnant from the
+// The low-level signal-based suspend/resume support is a remnant from the
// old VM-suspension that used to be for java-suspension, safepoints etc,
-// within hotspot. Now there is a single use-case for this:
-// - calling get_thread_pc() on the VMThread by the flat-profiler task
-// that runs in the watcher thread.
+// within hotspot. Currently used by JFR's OSThreadSampler
+//
// The remaining code is greatly simplified from the more general suspension
// code that used to be used.
//
@@ -2688,7 +2626,13 @@
//
// Note that the SR_lock plays no role in this suspend/resume protocol,
// but is checked for NULL in SR_handler as a thread termination indicator.
+// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
//
+// Note that resume_clear_context() and suspend_save_context() are needed
+// by SR_handler(), so that fetch_frame_from_ucontext() works,
+// which in part is used by:
+// - Forte Analyzer: AsyncGetCallTrace()
+// - StackBanging: get_frame_at_stack_banging_point()
static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL);
@@ -3695,44 +3639,6 @@
}
}
-class PcFetcher : public os::SuspendedThreadTask {
-public:
- PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
- ExtendedPC result();
-protected:
- void do_task(const os::SuspendedThreadTaskContext& context);
-private:
- ExtendedPC _epc;
-};
-
-ExtendedPC PcFetcher::result() {
- guarantee(is_done(), "task is not done yet.");
- return _epc;
-}
-
-void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
- Thread* thread = context.thread();
- OSThread* osthread = thread->osthread();
- if (osthread->ucontext() != NULL) {
- _epc = os::Aix::ucontext_get_pc((const ucontext_t *) context.ucontext());
- } else {
- // NULL context is unexpected, double-check this is the VMThread.
- guarantee(thread->is_VM_thread(), "can only be called for VMThread");
- }
-}
-
-// Suspends the target using the signal mechanism and then grabs the PC before
-// resuming the target. Used by the flat-profiler only
-ExtendedPC os::get_thread_pc(Thread* thread) {
- // Make sure that it is called by the watcher for the VMThread.
- assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
- assert(thread->is_VM_thread(), "Can only be called for VMThread");
-
- PcFetcher fetcher(thread);
- fetcher.run();
- return fetcher.result();
-}
-
////////////////////////////////////////////////////////////////////////////////
// debug support
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1172,13 +1172,6 @@
// DLL functions
-#define JNI_LIB_PREFIX "lib"
-#ifdef __APPLE__
- #define JNI_LIB_SUFFIX ".dylib"
-#else
- #define JNI_LIB_SUFFIX ".so"
-#endif
-
const char* os::dll_file_extension() { return JNI_LIB_SUFFIX; }
// This must be hard coded because it's the system's temporary
@@ -1201,62 +1194,6 @@
const char* os::get_temp_directory() { return "/tmp"; }
#endif // __APPLE__
-static bool file_exists(const char* filename) {
- struct stat statbuf;
- if (filename == NULL || strlen(filename) == 0) {
- return false;
- }
- return os::stat(filename, &statbuf) == 0;
-}
-
-bool os::dll_build_name(char* buffer, size_t buflen,
- const char* pname, const char* fname) {
- bool retval = false;
- // Copied from libhpi
- const size_t pnamelen = pname ? strlen(pname) : 0;
-
- // Return error on buffer overflow.
- if (pnamelen + strlen(fname) + strlen(JNI_LIB_PREFIX) + strlen(JNI_LIB_SUFFIX) + 2 > buflen) {
- return retval;
- }
-
- if (pnamelen == 0) {
- snprintf(buffer, buflen, JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX, fname);
- retval = true;
- } else if (strchr(pname, *os::path_separator()) != NULL) {
- int n;
- char** pelements = split_path(pname, &n);
- if (pelements == NULL) {
- return false;
- }
- for (int i = 0; i < n; i++) {
- // Really shouldn't be NULL, but check can't hurt
- if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
- continue; // skip the empty path values
- }
- snprintf(buffer, buflen, "%s/" JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX,
- pelements[i], fname);
- if (file_exists(buffer)) {
- retval = true;
- break;
- }
- }
- // release the storage
- for (int i = 0; i < n; i++) {
- if (pelements[i] != NULL) {
- FREE_C_HEAP_ARRAY(char, pelements[i]);
- }
- }
- if (pelements != NULL) {
- FREE_C_HEAP_ARRAY(char*, pelements);
- }
- } else {
- snprintf(buffer, buflen, "%s/" JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX, pname, fname);
- retval = true;
- }
- return retval;
-}
-
// check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr;
@@ -2666,11 +2603,10 @@
////////////////////////////////////////////////////////////////////////////////
// suspend/resume support
-// the low-level signal-based suspend/resume support is a remnant from the
+// The low-level signal-based suspend/resume support is a remnant from the
// old VM-suspension that used to be for java-suspension, safepoints etc,
-// within hotspot. Now there is a single use-case for this:
-// - calling get_thread_pc() on the VMThread by the flat-profiler task
-// that runs in the watcher thread.
+// within hotspot. Currently used by JFR's OSThreadSampler
+//
// The remaining code is greatly simplified from the more general suspension
// code that used to be used.
//
@@ -2686,6 +2622,13 @@
//
// Note that the SR_lock plays no role in this suspend/resume protocol,
// but is checked for NULL in SR_handler as a thread termination indicator.
+// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
+//
+// Note that resume_clear_context() and suspend_save_context() are needed
+// by SR_handler(), so that fetch_frame_from_ucontext() works,
+// which in part is used by:
+// - Forte Analyzer: AsyncGetCallTrace()
+// - StackBanging: get_frame_at_stack_banging_point()
static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL);
@@ -3584,45 +3527,6 @@
}
}
-///
-class PcFetcher : public os::SuspendedThreadTask {
- public:
- PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
- ExtendedPC result();
- protected:
- void do_task(const os::SuspendedThreadTaskContext& context);
- private:
- ExtendedPC _epc;
-};
-
-ExtendedPC PcFetcher::result() {
- guarantee(is_done(), "task is not done yet.");
- return _epc;
-}
-
-void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
- Thread* thread = context.thread();
- OSThread* osthread = thread->osthread();
- if (osthread->ucontext() != NULL) {
- _epc = os::Bsd::ucontext_get_pc((const ucontext_t *) context.ucontext());
- } else {
- // NULL context is unexpected, double-check this is the VMThread
- guarantee(thread->is_VM_thread(), "can only be called for VMThread");
- }
-}
-
-// Suspends the target using the signal mechanism and then grabs the PC before
-// resuming the target. Used by the flat-profiler only
-ExtendedPC os::get_thread_pc(Thread* thread) {
- // Make sure that it is called by the watcher for the VMThread
- assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
- assert(thread->is_VM_thread(), "Can only be called for VMThread");
-
- PcFetcher fetcher(thread);
- fetcher.run();
- return fetcher.result();
-}
-
////////////////////////////////////////////////////////////////////////////////
// debug support
--- a/hotspot/src/os/linux/vm/os_linux.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1419,53 +1419,6 @@
return os::stat(filename, &statbuf) == 0;
}
-bool os::dll_build_name(char* buffer, size_t buflen,
- const char* pname, const char* fname) {
- bool retval = false;
- // Copied from libhpi
- const size_t pnamelen = pname ? strlen(pname) : 0;
-
- // Return error on buffer overflow.
- if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
- return retval;
- }
-
- if (pnamelen == 0) {
- snprintf(buffer, buflen, "lib%s.so", fname);
- retval = true;
- } else if (strchr(pname, *os::path_separator()) != NULL) {
- int n;
- char** pelements = split_path(pname, &n);
- if (pelements == NULL) {
- return false;
- }
- for (int i = 0; i < n; i++) {
- // Really shouldn't be NULL, but check can't hurt
- if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
- continue; // skip the empty path values
- }
- snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
- if (file_exists(buffer)) {
- retval = true;
- break;
- }
- }
- // release the storage
- for (int i = 0; i < n; i++) {
- if (pelements[i] != NULL) {
- FREE_C_HEAP_ARRAY(char, pelements[i]);
- }
- }
- if (pelements != NULL) {
- FREE_C_HEAP_ARRAY(char*, pelements);
- }
- } else {
- snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
- retval = true;
- }
- return retval;
-}
-
// check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr;
@@ -4047,11 +4000,10 @@
////////////////////////////////////////////////////////////////////////////////
// suspend/resume support
-// the low-level signal-based suspend/resume support is a remnant from the
+// The low-level signal-based suspend/resume support is a remnant from the
// old VM-suspension that used to be for java-suspension, safepoints etc,
-// within hotspot. Now there is a single use-case for this:
-// - calling get_thread_pc() on the VMThread by the flat-profiler task
-// that runs in the watcher thread.
+// within hotspot. Currently used by JFR's OSThreadSampler
+//
// The remaining code is greatly simplified from the more general suspension
// code that used to be used.
//
@@ -4067,6 +4019,13 @@
//
// Note that the SR_lock plays no role in this suspend/resume protocol,
// but is checked for NULL in SR_handler as a thread termination indicator.
+// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
+//
+// Note that resume_clear_context() and suspend_save_context() are needed
+// by SR_handler(), so that fetch_frame_from_ucontext() works,
+// which in part is used by:
+// - Forte Analyzer: AsyncGetCallTrace()
+// - StackBanging: get_frame_at_stack_banging_point()
static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL);
@@ -5107,44 +5066,6 @@
}
}
-class PcFetcher : public os::SuspendedThreadTask {
- public:
- PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
- ExtendedPC result();
- protected:
- void do_task(const os::SuspendedThreadTaskContext& context);
- private:
- ExtendedPC _epc;
-};
-
-ExtendedPC PcFetcher::result() {
- guarantee(is_done(), "task is not done yet.");
- return _epc;
-}
-
-void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
- Thread* thread = context.thread();
- OSThread* osthread = thread->osthread();
- if (osthread->ucontext() != NULL) {
- _epc = os::Linux::ucontext_get_pc((const ucontext_t *) context.ucontext());
- } else {
- // NULL context is unexpected, double-check this is the VMThread
- guarantee(thread->is_VM_thread(), "can only be called for VMThread");
- }
-}
-
-// Suspends the target using the signal mechanism and then grabs the PC before
-// resuming the target. Used by the flat-profiler only
-ExtendedPC os::get_thread_pc(Thread* thread) {
- // Make sure that it is called by the watcher for the VMThread
- assert(Thread::current()->is_Watcher_thread(), "Must be watcher");
- assert(thread->is_VM_thread(), "Can only be called for VMThread");
-
- PcFetcher fetcher(thread);
- fetcher.run();
- return fetcher.result();
-}
-
////////////////////////////////////////////////////////////////////////////////
// debug support
--- a/hotspot/src/os/posix/vm/os_posix.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os/posix/vm/os_posix.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -24,7 +24,6 @@
#include "utilities/globalDefinitions.hpp"
#include "prims/jvm.h"
-#include "semaphore_posix.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/os.hpp"
@@ -32,6 +31,11 @@
#include "utilities/macros.hpp"
#include "utilities/vmError.hpp"
+#ifndef __APPLE__
+// POSIX unamed semaphores are not supported on OS X.
+#include "semaphore_posix.hpp"
+#endif
+
#include <dlfcn.h>
#include <pthread.h>
#include <semaphore.h>
--- a/hotspot/src/os/solaris/vm/osThread_solaris.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os/solaris/vm/osThread_solaris.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -65,12 +65,6 @@
void set_lwp_id(uint id) { _lwp_id = id; }
void set_native_priority(int prio) { _native_priority = prio; }
- // ***************************************************************
- // interrupt support. interrupts (using signals) are used to get
- // the thread context (get_thread_pc), to set the thread context
- // (set_thread_pc), and to implement java.lang.Thread.interrupt.
- // ***************************************************************
-
public:
os::SuspendResume sr;
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1356,60 +1356,6 @@
// directory not the java application's temp directory, ala java.io.tmpdir.
const char* os::get_temp_directory() { return "/tmp"; }
-static bool file_exists(const char* filename) {
- struct stat statbuf;
- if (filename == NULL || strlen(filename) == 0) {
- return false;
- }
- return os::stat(filename, &statbuf) == 0;
-}
-
-bool os::dll_build_name(char* buffer, size_t buflen,
- const char* pname, const char* fname) {
- bool retval = false;
- const size_t pnamelen = pname ? strlen(pname) : 0;
-
- // Return error on buffer overflow.
- if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
- return retval;
- }
-
- if (pnamelen == 0) {
- snprintf(buffer, buflen, "lib%s.so", fname);
- retval = true;
- } else if (strchr(pname, *os::path_separator()) != NULL) {
- int n;
- char** pelements = split_path(pname, &n);
- if (pelements == NULL) {
- return false;
- }
- for (int i = 0; i < n; i++) {
- // really shouldn't be NULL but what the heck, check can't hurt
- if (pelements[i] == NULL || strlen(pelements[i]) == 0) {
- continue; // skip the empty path values
- }
- snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
- if (file_exists(buffer)) {
- retval = true;
- break;
- }
- }
- // release the storage
- for (int i = 0; i < n; i++) {
- if (pelements[i] != NULL) {
- FREE_C_HEAP_ARRAY(char, pelements[i]);
- }
- }
- if (pelements != NULL) {
- FREE_C_HEAP_ARRAY(char*, pelements);
- }
- } else {
- snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
- retval = true;
- }
- return retval;
-}
-
// check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr;
@@ -3496,6 +3442,37 @@
schedctl_start(schedctl_init());
}
+////////////////////////////////////////////////////////////////////////////////
+// suspend/resume support
+
+// The low-level signal-based suspend/resume support is a remnant from the
+// old VM-suspension that used to be for java-suspension, safepoints etc,
+// within hotspot. Currently used by JFR's OSThreadSampler
+//
+// The remaining code is greatly simplified from the more general suspension
+// code that used to be used.
+//
+// The protocol is quite simple:
+// - suspend:
+// - sends a signal to the target thread
+// - polls the suspend state of the osthread using a yield loop
+// - target thread signal handler (SR_handler) sets suspend state
+// and blocks in sigsuspend until continued
+// - resume:
+// - sets target osthread state to continue
+// - sends signal to end the sigsuspend loop in the SR_handler
+//
+// Note that the SR_lock plays no role in this suspend/resume protocol,
+// but is checked for NULL in SR_handler as a thread termination indicator.
+// The SR_lock is, however, used by JavaThread::java_suspend()/java_resume() APIs.
+//
+// Note that resume_clear_context() and suspend_save_context() are needed
+// by SR_handler(), so that fetch_frame_from_ucontext() works,
+// which in part is used by:
+// - Forte Analyzer: AsyncGetCallTrace()
+// - StackBanging: get_frame_at_stack_banging_point()
+// - JFR: get_topframe()-->....-->get_valid_uc_in_signal_handler()
+
static void resume_clear_context(OSThread *osthread) {
osthread->set_ucontext(NULL);
}
@@ -3506,7 +3483,7 @@
static PosixSemaphore sr_semaphore;
-void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) {
+void os::Solaris::SR_handler(Thread* thread, ucontext_t* context) {
// Save and restore errno to avoid confusing native code with EINTR
// after sigsuspend.
int old_errno = errno;
@@ -3516,7 +3493,7 @@
os::SuspendResume::State current = osthread->sr.state();
if (current == os::SuspendResume::SR_SUSPEND_REQUEST) {
- suspend_save_context(osthread, uc);
+ suspend_save_context(osthread, context);
// attempt to switch the state, we assume we had a SUSPEND_REQUEST
os::SuspendResume::State state = osthread->sr.suspended();
@@ -3663,45 +3640,6 @@
}
}
-class PcFetcher : public os::SuspendedThreadTask {
- public:
- PcFetcher(Thread* thread) : os::SuspendedThreadTask(thread) {}
- ExtendedPC result();
- protected:
- void do_task(const os::SuspendedThreadTaskContext& context);
- private:
- ExtendedPC _epc;
-};
-
-ExtendedPC PcFetcher::result() {
- guarantee(is_done(), "task is not done yet.");
- return _epc;
-}
-
-void PcFetcher::do_task(const os::SuspendedThreadTaskContext& context) {
- Thread* thread = context.thread();
- OSThread* osthread = thread->osthread();
- if (osthread->ucontext() != NULL) {
- _epc = os::Solaris::ucontext_get_pc((const ucontext_t *) context.ucontext());
- } else {
- // NULL context is unexpected, double-check this is the VMThread
- guarantee(thread->is_VM_thread(), "can only be called for VMThread");
- }
-}
-
-// A lightweight implementation that does not suspend the target thread and
-// thus returns only a hint. Used for profiling only!
-ExtendedPC os::get_thread_pc(Thread* thread) {
- // Make sure that it is called by the watcher and the Threads lock is owned.
- assert(Thread::current()->is_Watcher_thread(), "Must be watcher and own Threads_lock");
- // For now, is only used to profile the VM Thread
- assert(thread->is_VM_thread(), "Can only be called for VMThread");
- PcFetcher fetcher(thread);
- fetcher.run();
- return fetcher.result();
-}
-
-
// This does not do anything on Solaris. This is basically a hook for being
// able to use structured exception handling (thread-local exception filters) on, e.g., Win32.
void os::os_exception_wrapper(java_call_t f, JavaValue* value,
--- a/hotspot/src/os/windows/vm/decoder_windows.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os/windows/vm/decoder_windows.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,160 +27,99 @@
#include "runtime/arguments.hpp"
#include "runtime/os.hpp"
#include "decoder_windows.hpp"
+#include "windbghelp.hpp"
WindowsDecoder::WindowsDecoder() {
- _dbghelp_handle = NULL;
- _can_decode_in_vm = false;
- _pfnSymGetSymFromAddr64 = NULL;
- _pfnUndecorateSymbolName = NULL;
-#ifdef AMD64
- _pfnStackWalk64 = NULL;
- _pfnSymFunctionTableAccess64 = NULL;
- _pfnSymGetModuleBase64 = NULL;
-#endif
+ _can_decode_in_vm = true;
_decoder_status = no_error;
initialize();
}
void WindowsDecoder::initialize() {
- if (!has_error() && _dbghelp_handle == NULL) {
- HMODULE handle = ::LoadLibrary("dbghelp.dll");
- if (!handle) {
- _decoder_status = helper_not_found;
- return;
- }
-
- _dbghelp_handle = handle;
-
- pfn_SymSetOptions _pfnSymSetOptions = (pfn_SymSetOptions)::GetProcAddress(handle, "SymSetOptions");
- pfn_SymInitialize _pfnSymInitialize = (pfn_SymInitialize)::GetProcAddress(handle, "SymInitialize");
- _pfnSymGetSymFromAddr64 = (pfn_SymGetSymFromAddr64)::GetProcAddress(handle, "SymGetSymFromAddr64");
- _pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)::GetProcAddress(handle, "UnDecorateSymbolName");
-
- if (_pfnSymSetOptions == NULL || _pfnSymInitialize == NULL || _pfnSymGetSymFromAddr64 == NULL) {
- uninitialize();
- _decoder_status = helper_func_error;
- return;
- }
-
-#ifdef AMD64
- _pfnStackWalk64 = (pfn_StackWalk64)::GetProcAddress(handle, "StackWalk64");
- _pfnSymFunctionTableAccess64 = (pfn_SymFunctionTableAccess64)::GetProcAddress(handle, "SymFunctionTableAccess64");
- _pfnSymGetModuleBase64 = (pfn_SymGetModuleBase64)::GetProcAddress(handle, "SymGetModuleBase64");
- if (_pfnStackWalk64 == NULL || _pfnSymFunctionTableAccess64 == NULL || _pfnSymGetModuleBase64 == NULL) {
- // We can't call StackWalk64 to walk the stack, but we are still
- // able to decode the symbols. Let's limp on.
- _pfnStackWalk64 = NULL;
- _pfnSymFunctionTableAccess64 = NULL;
- _pfnSymGetModuleBase64 = NULL;
- }
-#endif
-
+ if (!has_error()) {
HANDLE hProcess = ::GetCurrentProcess();
- _pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS);
- if (!_pfnSymInitialize(hProcess, NULL, TRUE)) {
- _pfnSymGetSymFromAddr64 = NULL;
- _pfnUndecorateSymbolName = NULL;
- ::FreeLibrary(handle);
- _dbghelp_handle = NULL;
+ WindowsDbgHelp::symSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS);
+ if (!WindowsDbgHelp::symInitialize(hProcess, NULL, TRUE)) {
_decoder_status = helper_init_error;
return;
}
// set pdb search paths
- pfn_SymSetSearchPath _pfn_SymSetSearchPath =
- (pfn_SymSetSearchPath)::GetProcAddress(handle, "SymSetSearchPath");
- pfn_SymGetSearchPath _pfn_SymGetSearchPath =
- (pfn_SymGetSearchPath)::GetProcAddress(handle, "SymGetSearchPath");
- if (_pfn_SymSetSearchPath != NULL && _pfn_SymGetSearchPath != NULL) {
- char paths[MAX_PATH];
- int len = sizeof(paths);
- if (!_pfn_SymGetSearchPath(hProcess, paths, len)) {
- paths[0] = '\0';
- } else {
- // available spaces in path buffer
- len -= (int)strlen(paths);
- }
+ char paths[MAX_PATH];
+ int len = sizeof(paths);
+ if (!WindowsDbgHelp::symGetSearchPath(hProcess, paths, len)) {
+ paths[0] = '\0';
+ } else {
+ // available spaces in path buffer
+ len -= (int)strlen(paths);
+ }
- char tmp_path[MAX_PATH];
- DWORD dwSize;
- HMODULE hJVM = ::GetModuleHandle("jvm.dll");
- tmp_path[0] = '\0';
- // append the path where jvm.dll is located
- if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) {
- while (dwSize > 0 && tmp_path[dwSize] != '\\') {
- dwSize --;
- }
-
- tmp_path[dwSize] = '\0';
-
- if (dwSize > 0 && len > (int)dwSize + 1) {
- strncat(paths, os::path_separator(), 1);
- strncat(paths, tmp_path, dwSize);
- len -= dwSize + 1;
- }
+ char tmp_path[MAX_PATH];
+ DWORD dwSize;
+ HMODULE hJVM = ::GetModuleHandle("jvm.dll");
+ tmp_path[0] = '\0';
+ // append the path where jvm.dll is located
+ if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) {
+ while (dwSize > 0 && tmp_path[dwSize] != '\\') {
+ dwSize --;
}
- // append $JRE/bin. Arguments::get_java_home actually returns $JRE
- // path
- char *p = Arguments::get_java_home();
- assert(p != NULL, "empty java home");
- size_t java_home_len = strlen(p);
- if (len > (int)java_home_len + 5) {
+ tmp_path[dwSize] = '\0';
+
+ if (dwSize > 0 && len > (int)dwSize + 1) {
strncat(paths, os::path_separator(), 1);
- strncat(paths, p, java_home_len);
- strncat(paths, "\\bin", 4);
- len -= (int)(java_home_len + 5);
+ strncat(paths, tmp_path, dwSize);
+ len -= dwSize + 1;
}
+ }
- // append $JDK/bin path if it exists
- assert(java_home_len < MAX_PATH, "Invalid path length");
- // assume $JRE is under $JDK, construct $JDK/bin path and
- // see if it exists or not
- if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) {
- strncpy(tmp_path, p, java_home_len - 3);
- tmp_path[java_home_len - 3] = '\0';
- strncat(tmp_path, "bin", 3);
+ // append $JRE/bin. Arguments::get_java_home actually returns $JRE
+ // path
+ char *p = Arguments::get_java_home();
+ assert(p != NULL, "empty java home");
+ size_t java_home_len = strlen(p);
+ if (len > (int)java_home_len + 5) {
+ strncat(paths, os::path_separator(), 1);
+ strncat(paths, p, java_home_len);
+ strncat(paths, "\\bin", 4);
+ len -= (int)(java_home_len + 5);
+ }
- // if the directory exists
- DWORD dwAttrib = GetFileAttributes(tmp_path);
- if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
- (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
- // tmp_path should have the same length as java_home_len, since we only
- // replaced 'jre' with 'bin'
- if (len > (int)java_home_len + 1) {
- strncat(paths, os::path_separator(), 1);
- strncat(paths, tmp_path, java_home_len);
- }
+ // append $JDK/bin path if it exists
+ assert(java_home_len < MAX_PATH, "Invalid path length");
+ // assume $JRE is under $JDK, construct $JDK/bin path and
+ // see if it exists or not
+ if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) {
+ strncpy(tmp_path, p, java_home_len - 3);
+ tmp_path[java_home_len - 3] = '\0';
+ strncat(tmp_path, "bin", 3);
+
+ // if the directory exists
+ DWORD dwAttrib = GetFileAttributes(tmp_path);
+ if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
+ (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
+ // tmp_path should have the same length as java_home_len, since we only
+ // replaced 'jre' with 'bin'
+ if (len > (int)java_home_len + 1) {
+ strncat(paths, os::path_separator(), 1);
+ strncat(paths, tmp_path, java_home_len);
}
}
-
- _pfn_SymSetSearchPath(hProcess, paths);
}
- // find out if jvm.dll contains private symbols, by decoding
- // current function and comparing the result
- address addr = (address)Decoder::demangle;
- char buf[MAX_PATH];
- if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) {
- _can_decode_in_vm = !strcmp(buf, "Decoder::demangle");
- }
+ WindowsDbgHelp::symSetSearchPath(hProcess, paths);
+
+ // find out if jvm.dll contains private symbols, by decoding
+ // current function and comparing the result
+ address addr = (address)Decoder::demangle;
+ char buf[MAX_PATH];
+ if (decode(addr, buf, sizeof(buf), NULL, NULL, true /* demangle */)) {
+ _can_decode_in_vm = !strcmp(buf, "Decoder::demangle");
+ }
}
}
-void WindowsDecoder::uninitialize() {
- _pfnSymGetSymFromAddr64 = NULL;
- _pfnUndecorateSymbolName = NULL;
-#ifdef AMD64
- _pfnStackWalk64 = NULL;
- _pfnSymFunctionTableAccess64 = NULL;
- _pfnSymGetModuleBase64 = NULL;
-#endif
- if (_dbghelp_handle != NULL) {
- ::FreeLibrary(_dbghelp_handle);
- }
- _dbghelp_handle = NULL;
-}
+void WindowsDecoder::uninitialize() {}
bool WindowsDecoder::can_decode_C_frame_in_vm() const {
return (!has_error() && _can_decode_in_vm);
@@ -188,14 +127,14 @@
bool WindowsDecoder::decode(address addr, char *buf, int buflen, int* offset, const char* modulepath, bool demangle_name) {
- if (_pfnSymGetSymFromAddr64 != NULL) {
+ if (!has_error()) {
PIMAGEHLP_SYMBOL64 pSymbol;
char symbolInfo[MAX_PATH + sizeof(IMAGEHLP_SYMBOL64)];
pSymbol = (PIMAGEHLP_SYMBOL64)symbolInfo;
pSymbol->MaxNameLength = MAX_PATH;
pSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
DWORD64 displacement;
- if (_pfnSymGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
+ if (WindowsDbgHelp::symGetSymFromAddr64(::GetCurrentProcess(), (DWORD64)addr, &displacement, pSymbol)) {
if (buf != NULL) {
if (!(demangle_name && demangle(pSymbol->Name, buf, buflen))) {
jio_snprintf(buf, buflen, "%s", pSymbol->Name);
@@ -211,69 +150,9 @@
}
bool WindowsDecoder::demangle(const char* symbol, char *buf, int buflen) {
- return _pfnUndecorateSymbolName != NULL &&
- _pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE);
-}
-
-#ifdef AMD64
-BOOL WindowsDbgHelp::StackWalk64(DWORD MachineType,
- HANDLE hProcess,
- HANDLE hThread,
- LPSTACKFRAME64 StackFrame,
- PVOID ContextRecord,
- PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
- PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
- PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
- PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress) {
- DecoderLocker locker;
- WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
-
- if (!wd->has_error() && wd->_pfnStackWalk64) {
- return wd->_pfnStackWalk64(MachineType,
- hProcess,
- hThread,
- StackFrame,
- ContextRecord,
- ReadMemoryRoutine,
- FunctionTableAccessRoutine,
- GetModuleBaseRoutine,
- TranslateAddress);
- } else {
- return false;
+ if (!has_error()) {
+ return WindowsDbgHelp::unDecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE) > 0;
}
+ return false;
}
-PVOID WindowsDbgHelp::SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) {
- DecoderLocker locker;
- WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
-
- if (!wd->has_error() && wd->_pfnSymFunctionTableAccess64) {
- return wd->_pfnSymFunctionTableAccess64(hProcess, AddrBase);
- } else {
- return NULL;
- }
-}
-
-pfn_SymFunctionTableAccess64 WindowsDbgHelp::pfnSymFunctionTableAccess64() {
- DecoderLocker locker;
- WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
-
- if (!wd->has_error()) {
- return wd->_pfnSymFunctionTableAccess64;
- } else {
- return NULL;
- }
-}
-
-pfn_SymGetModuleBase64 WindowsDbgHelp::pfnSymGetModuleBase64() {
- DecoderLocker locker;
- WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
-
- if (!wd->has_error()) {
- return wd->_pfnSymGetModuleBase64;
- } else {
- return NULL;
- }
-}
-
-#endif // AMD64
--- a/hotspot/src/os/windows/vm/decoder_windows.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os/windows/vm/decoder_windows.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -25,33 +25,8 @@
#ifndef OS_WINDOWS_VM_DECODER_WINDOWS_HPP
#define OS_WINDOWS_VM_DECIDER_WINDOWS_HPP
-#include <windows.h>
-#include <imagehlp.h>
-
#include "utilities/decoder.hpp"
-// functions needed for decoding symbols
-typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD);
-typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL);
-typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
-typedef DWORD (WINAPI *pfn_UndecorateSymbolName)(const char*, char*, DWORD, DWORD);
-typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR);
-typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int);
-
-#ifdef AMD64
-typedef BOOL (WINAPI *pfn_StackWalk64)(DWORD MachineType,
- HANDLE hProcess,
- HANDLE hThread,
- LPSTACKFRAME64 StackFrame,
- PVOID ContextRecord,
- PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
- PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
- PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
- PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
-typedef PVOID (WINAPI *pfn_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase);
-typedef DWORD64 (WINAPI *pfn_SymGetModuleBase64)(HANDLE hProcess, DWORD64 dwAddr);
-#endif
-
class WindowsDecoder : public AbstractDecoder {
public:
@@ -70,38 +45,8 @@
void initialize();
void uninitialize();
-private:
- HMODULE _dbghelp_handle;
bool _can_decode_in_vm;
- pfn_SymGetSymFromAddr64 _pfnSymGetSymFromAddr64;
- pfn_UndecorateSymbolName _pfnUndecorateSymbolName;
-#ifdef AMD64
- pfn_StackWalk64 _pfnStackWalk64;
- pfn_SymFunctionTableAccess64 _pfnSymFunctionTableAccess64;
- pfn_SymGetModuleBase64 _pfnSymGetModuleBase64;
- friend class WindowsDbgHelp;
-#endif
};
-#ifdef AMD64
-// TODO: refactor and move the handling of dbghelp.dll outside of Decoder
-class WindowsDbgHelp : public Decoder {
-public:
- static BOOL StackWalk64(DWORD MachineType,
- HANDLE hProcess,
- HANDLE hThread,
- LPSTACKFRAME64 StackFrame,
- PVOID ContextRecord,
- PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
- PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
- PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
- PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
- static PVOID SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
-
- static pfn_SymFunctionTableAccess64 pfnSymFunctionTableAccess64();
- static pfn_SymGetModuleBase64 pfnSymGetModuleBase64();
-};
-#endif
-
#endif // OS_WINDOWS_VM_DECODER_WINDOWS_HPP
--- a/hotspot/src/os/windows/vm/os_windows.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -74,6 +74,8 @@
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
#include "utilities/vmError.hpp"
+#include "windbghelp.hpp"
+
#ifdef _DEBUG
#include <crtdbg.h>
@@ -1009,7 +1011,6 @@
}
void os::abort(bool dump_core, void* siginfo, const void* context) {
- HINSTANCE dbghelp;
EXCEPTION_POINTERS ep;
MINIDUMP_EXCEPTION_INFORMATION mei;
MINIDUMP_EXCEPTION_INFORMATION* pmei;
@@ -1026,28 +1027,6 @@
win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
}
- dbghelp = os::win32::load_Windows_dll("DBGHELP.DLL", NULL, 0);
-
- if (dbghelp == NULL) {
- jio_fprintf(stderr, "Failed to load dbghelp.dll\n");
- CloseHandle(dumpFile);
- win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
- }
-
- _MiniDumpWriteDump =
- CAST_TO_FN_PTR(BOOL(WINAPI *)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
- PMINIDUMP_EXCEPTION_INFORMATION,
- PMINIDUMP_USER_STREAM_INFORMATION,
- PMINIDUMP_CALLBACK_INFORMATION),
- GetProcAddress(dbghelp,
- "MiniDumpWriteDump"));
-
- if (_MiniDumpWriteDump == NULL) {
- jio_fprintf(stderr, "Failed to find MiniDumpWriteDump() in module dbghelp.dll.\n");
- CloseHandle(dumpFile);
- win32::exit_process_or_thread(win32::EPT_PROCESS, 1);
- }
-
dumpType = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData |
MiniDumpWithFullMemoryInfo | MiniDumpWithThreadInfo | MiniDumpWithUnloadedModules);
@@ -1064,8 +1043,8 @@
// Older versions of dbghelp.dll (the one shipped with Win2003 for example) may not support all
// the dump types we really want. If first call fails, lets fall back to just use MiniDumpWithFullMemory then.
- if (_MiniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) == false &&
- _MiniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL) == false) {
+ if (!WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, dumpType, pmei, NULL, NULL) &&
+ !WindowsDbgHelp::miniDumpWriteDump(hProcess, processId, dumpFile, (MINIDUMP_TYPE)MiniDumpWithFullMemory, pmei, NULL, NULL)) {
jio_fprintf(stderr, "Call to MiniDumpWriteDump() failed (Error 0x%x)\n", GetLastError());
}
CloseHandle(dumpFile);
@@ -1198,70 +1177,6 @@
}
}
-static bool file_exists(const char* filename) {
- if (filename == NULL || strlen(filename) == 0) {
- return false;
- }
- return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
-}
-
-bool os::dll_build_name(char *buffer, size_t buflen,
- const char* pname, const char* fname) {
- bool retval = false;
- const size_t pnamelen = pname ? strlen(pname) : 0;
- const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
-
- // Return error on buffer overflow.
- if (pnamelen + strlen(fname) + 10 > buflen) {
- return retval;
- }
-
- if (pnamelen == 0) {
- jio_snprintf(buffer, buflen, "%s.dll", fname);
- retval = true;
- } else if (c == ':' || c == '\\') {
- jio_snprintf(buffer, buflen, "%s%s.dll", pname, fname);
- retval = true;
- } else if (strchr(pname, *os::path_separator()) != NULL) {
- int n;
- char** pelements = split_path(pname, &n);
- if (pelements == NULL) {
- return false;
- }
- for (int i = 0; i < n; i++) {
- char* path = pelements[i];
- // Really shouldn't be NULL, but check can't hurt
- size_t plen = (path == NULL) ? 0 : strlen(path);
- if (plen == 0) {
- continue; // skip the empty path values
- }
- const char lastchar = path[plen - 1];
- if (lastchar == ':' || lastchar == '\\') {
- jio_snprintf(buffer, buflen, "%s%s.dll", path, fname);
- } else {
- jio_snprintf(buffer, buflen, "%s\\%s.dll", path, fname);
- }
- if (file_exists(buffer)) {
- retval = true;
- break;
- }
- }
- // release the storage
- for (int i = 0; i < n; i++) {
- if (pelements[i] != NULL) {
- FREE_C_HEAP_ARRAY(char, pelements[i]);
- }
- }
- if (pelements != NULL) {
- FREE_C_HEAP_ARRAY(char*, pelements);
- }
- } else {
- jio_snprintf(buffer, buflen, "%s\\%s.dll", pname, fname);
- retval = true;
- }
- return retval;
-}
-
// Needs to be in os specific directory because windows requires another
// header file <direct.h>
const char* os::get_current_directory(char *buf, size_t buflen) {
@@ -3591,22 +3506,6 @@
return interrupted;
}
-// Get's a pc (hint) for a running thread. Currently used only for profiling.
-ExtendedPC os::get_thread_pc(Thread* thread) {
- CONTEXT context;
- context.ContextFlags = CONTEXT_CONTROL;
- HANDLE handle = thread->osthread()->thread_handle();
- if (GetThreadContext(handle, &context)) {
-#ifdef _M_AMD64
- return ExtendedPC((address) context.Rip);
-#else
- return ExtendedPC((address) context.Eip);
-#endif
- } else {
- return ExtendedPC(NULL);
- }
-}
-
// GetCurrentThreadId() returns DWORD
intx os::current_thread_id() { return GetCurrentThreadId(); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/windows/vm/windbghelp.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2017, 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 "utilities/ostream.hpp"
+#include "windbghelp.hpp"
+
+#include <windows.h>
+
+typedef DWORD (WINAPI *pfn_SymSetOptions)(DWORD);
+typedef DWORD (WINAPI *pfn_SymGetOptions)(void);
+typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL);
+typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
+typedef DWORD (WINAPI *pfn_UnDecorateSymbolName)(const char*, char*, DWORD, DWORD);
+typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR);
+typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int);
+typedef BOOL (WINAPI *pfn_StackWalk64)(DWORD MachineType,
+ HANDLE hProcess,
+ HANDLE hThread,
+ LPSTACKFRAME64 StackFrame,
+ PVOID ContextRecord,
+ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
+typedef PVOID (WINAPI *pfn_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase);
+typedef DWORD64 (WINAPI *pfn_SymGetModuleBase64)(HANDLE hProcess, DWORD64 dwAddr);
+typedef BOOL (WINAPI *pfn_MiniDumpWriteDump) (HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
+ MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+typedef BOOL (WINAPI *pfn_SymGetLineFromAddr64) (HANDLE hProcess, DWORD64 dwAddr,
+ PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line);
+typedef LPAPI_VERSION (WINAPI *pfn_ImagehlpApiVersion)(void);
+
+// Add functions as needed.
+#define FOR_ALL_FUNCTIONS(DO) \
+ DO(ImagehlpApiVersion) \
+ DO(SymGetOptions) \
+ DO(SymSetOptions) \
+ DO(SymInitialize) \
+ DO(SymGetSymFromAddr64) \
+ DO(UnDecorateSymbolName) \
+ DO(SymSetSearchPath) \
+ DO(SymGetSearchPath) \
+ DO(StackWalk64) \
+ DO(SymFunctionTableAccess64) \
+ DO(SymGetModuleBase64) \
+ DO(MiniDumpWriteDump) \
+ DO(SymGetLineFromAddr64)
+
+
+#define DECLARE_FUNCTION_POINTER(functionname) \
+static pfn_##functionname g_pfn_##functionname;
+
+FOR_ALL_FUNCTIONS(DECLARE_FUNCTION_POINTER)
+
+
+static HMODULE g_dll_handle = NULL;
+static DWORD g_dll_load_error = 0;
+static API_VERSION g_version = { 0, 0, 0, 0 };
+
+static enum {
+ state_uninitialized = 0,
+ state_ready = 1,
+ state_error = 2
+} g_state = state_uninitialized;
+
+static void initialize() {
+
+ assert(g_state == state_uninitialized, "wrong sequence");
+ g_state = state_error;
+
+ g_dll_handle = ::LoadLibrary("DBGHELP.DLL");
+ if (g_dll_handle == NULL) {
+ g_dll_load_error = ::GetLastError();
+ } else {
+ // Note: We loaded the DLL successfully. From here on we count
+ // initialization as success. We still may fail to load all of the
+ // desired function pointers successfully, but DLL may still be usable
+ // enough for our purposes.
+ g_state = state_ready;
+
+#define DO_RESOLVE(functionname) \
+ g_pfn_##functionname = (pfn_##functionname) ::GetProcAddress(g_dll_handle, #functionname);
+
+ FOR_ALL_FUNCTIONS(DO_RESOLVE)
+
+ // Retrieve version information.
+ if (g_pfn_ImagehlpApiVersion) {
+ const API_VERSION* p = g_pfn_ImagehlpApiVersion();
+ memcpy(&g_version, p, sizeof(API_VERSION));
+ }
+ }
+
+}
+
+///////////////////// External functions //////////////////////////
+
+// All outside facing functions are synchronized. Also, we run
+// initialization on first touch.
+
+
+// Call InitializeCriticalSection as early as possible.
+class CritSect {
+ CRITICAL_SECTION cs;
+public:
+ CritSect() { ::InitializeCriticalSection(&cs); }
+ void enter() { ::EnterCriticalSection(&cs); }
+ void leave() { ::LeaveCriticalSection(&cs); }
+};
+
+static CritSect g_cs;
+
+class EntryGuard {
+public:
+ EntryGuard() {
+ g_cs.enter();
+ if (g_state == state_uninitialized) {
+ initialize();
+ }
+ }
+ ~EntryGuard() {
+ g_cs.leave();
+ }
+};
+
+DWORD WindowsDbgHelp::symSetOptions(DWORD arg) {
+ EntryGuard entry_guard;
+ if (g_pfn_SymSetOptions != NULL) {
+ return g_pfn_SymSetOptions(arg);
+ }
+ return 0;
+}
+
+DWORD WindowsDbgHelp::symGetOptions(void) {
+ EntryGuard entry_guard;
+ if (g_pfn_SymGetOptions != NULL) {
+ return g_pfn_SymGetOptions();
+ }
+ return 0;
+}
+
+BOOL WindowsDbgHelp::symInitialize(HANDLE hProcess, PCTSTR UserSearchPath, BOOL fInvadeProcess) {
+ EntryGuard entry_guard;
+ if (g_pfn_SymInitialize != NULL) {
+ return g_pfn_SymInitialize(hProcess, UserSearchPath, fInvadeProcess);
+ }
+ return FALSE;
+}
+
+BOOL WindowsDbgHelp::symGetSymFromAddr64(HANDLE hProcess, DWORD64 the_address,
+ PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol) {
+ EntryGuard entry_guard;
+ if (g_pfn_SymGetSymFromAddr64 != NULL) {
+ return g_pfn_SymGetSymFromAddr64(hProcess, the_address, Displacement, Symbol);
+ }
+ return FALSE;
+}
+
+DWORD WindowsDbgHelp::unDecorateSymbolName(const char* DecoratedName, char* UnDecoratedName,
+ DWORD UndecoratedLength, DWORD Flags) {
+ EntryGuard entry_guard;
+ if (g_pfn_UnDecorateSymbolName != NULL) {
+ return g_pfn_UnDecorateSymbolName(DecoratedName, UnDecoratedName, UndecoratedLength, Flags);
+ }
+ if (UnDecoratedName != NULL && UndecoratedLength > 0) {
+ UnDecoratedName[0] = '\0';
+ }
+ return 0;
+}
+
+BOOL WindowsDbgHelp::symSetSearchPath(HANDLE hProcess, PCTSTR SearchPath) {
+ EntryGuard entry_guard;
+ if (g_pfn_SymSetSearchPath != NULL) {
+ return g_pfn_SymSetSearchPath(hProcess, SearchPath);
+ }
+ return FALSE;
+}
+
+BOOL WindowsDbgHelp::symGetSearchPath(HANDLE hProcess, PTSTR SearchPath, int SearchPathLength) {
+ EntryGuard entry_guard;
+ if (g_pfn_SymGetSearchPath != NULL) {
+ return g_pfn_SymGetSearchPath(hProcess, SearchPath, SearchPathLength);
+ }
+ return FALSE;
+}
+
+BOOL WindowsDbgHelp::stackWalk64(DWORD MachineType,
+ HANDLE hProcess,
+ HANDLE hThread,
+ LPSTACKFRAME64 StackFrame,
+ PVOID ContextRecord) {
+ EntryGuard entry_guard;
+ if (g_pfn_StackWalk64 != NULL) {
+ return g_pfn_StackWalk64(MachineType, hProcess, hThread, StackFrame,
+ ContextRecord,
+ NULL, // ReadMemoryRoutine
+ g_pfn_SymFunctionTableAccess64, // FunctionTableAccessRoutine,
+ g_pfn_SymGetModuleBase64, // GetModuleBaseRoutine
+ NULL // TranslateAddressRoutine
+ );
+ }
+ return FALSE;
+}
+
+PVOID WindowsDbgHelp::symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) {
+ EntryGuard entry_guard;
+ if (g_pfn_SymFunctionTableAccess64 != NULL) {
+ return g_pfn_SymFunctionTableAccess64(hProcess, AddrBase);
+ }
+ return NULL;
+}
+
+DWORD64 WindowsDbgHelp::symGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr) {
+ EntryGuard entry_guard;
+ if (g_pfn_SymGetModuleBase64 != NULL) {
+ return g_pfn_SymGetModuleBase64(hProcess, dwAddr);
+ }
+ return 0;
+}
+
+BOOL WindowsDbgHelp::miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
+ MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ PMINIDUMP_CALLBACK_INFORMATION CallbackParam) {
+ EntryGuard entry_guard;
+ if (g_pfn_MiniDumpWriteDump != NULL) {
+ return g_pfn_MiniDumpWriteDump(hProcess, ProcessId, hFile, DumpType,
+ ExceptionParam, UserStreamParam, CallbackParam);
+ }
+ return FALSE;
+}
+
+BOOL WindowsDbgHelp::symGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr,
+ PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) {
+ EntryGuard entry_guard;
+ if (g_pfn_SymGetLineFromAddr64 != NULL) {
+ return g_pfn_SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, Line);
+ }
+ return FALSE;
+}
+
+// Print one liner describing state (if library loaded, which functions are
+// missing - if any, and the dbhelp API version)
+void WindowsDbgHelp::print_state_on(outputStream* st) {
+ // Note: We should not lock while printing, but this should be
+ // safe to do without lock anyway.
+ st->print("dbghelp: ");
+
+ if (g_state == state_uninitialized) {
+ st->print("uninitialized.");
+ } else if (g_state == state_error) {
+ st->print("loading error: %u", g_dll_load_error);
+ } else {
+ st->print("loaded successfully ");
+
+ // We may want to print dll file name here - which may be interesting for
+ // cases where more than one version exists on the system, e.g. with a
+ // debugging sdk separately installed. But we get the file name in the DLL
+ // section of the hs-err file too, so this may be redundant.
+
+ // Print version.
+ st->print("- version: %u.%u.%u",
+ g_version.MajorVersion, g_version.MinorVersion, g_version.Revision);
+
+ // Print any functions which failed to load.
+ int num_missing = 0;
+ st->print(" - missing functions: ");
+
+ #define CHECK_AND_PRINT_IF_NULL(functionname) \
+ if (g_pfn_##functionname == NULL) { \
+ st->print("%s" #functionname, ((num_missing > 0) ? ", " : "")); \
+ num_missing ++; \
+ }
+
+ FOR_ALL_FUNCTIONS(CHECK_AND_PRINT_IF_NULL)
+
+ if (num_missing == 0) {
+ st->print("none");
+ }
+ }
+ st->cr();
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/os/windows/vm/windbghelp.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2017, 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_WINDOWS_VM_DBGHELPLOADER_HPP
+#define OS_WINDOWS_VM_DBGHELPLOADER_HPP
+
+#include <windows.h>
+#include <imagehlp.h>
+
+// This is a very plain wrapper for loading dbghelp.dll. It does not offer
+// any additional functionality. It takes care of locking.
+
+class outputStream;
+
+// Please note: dbghelp.dll may not have been loaded, or it may have been loaded but not
+// all functions may be available (because on the target system dbghelp.dll is of an
+// older version).
+// In all these cases we return an error from the WindowsDbgHelp::symXXXX() wrapper. We never
+// assert. It should always be safe to call these functions, but caller has to process the
+// return code (which he would have to do anyway).
+namespace WindowsDbgHelp {
+
+ DWORD symSetOptions(DWORD);
+ DWORD symGetOptions(void);
+ BOOL symInitialize(HANDLE, PCTSTR, BOOL);
+ BOOL symGetSymFromAddr64(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
+ DWORD unDecorateSymbolName(const char*, char*, DWORD, DWORD);
+ BOOL symSetSearchPath(HANDLE, PCTSTR);
+ BOOL symGetSearchPath(HANDLE, PTSTR, int);
+ BOOL stackWalk64(DWORD MachineType,
+ HANDLE hProcess,
+ HANDLE hThread,
+ LPSTACKFRAME64 StackFrame,
+ PVOID ContextRecord);
+ PVOID symFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
+ DWORD64 symGetModuleBase64(HANDLE hProcess, DWORD64 dwAddr);
+ BOOL miniDumpWriteDump(HANDLE hProcess, DWORD ProcessId, HANDLE hFile,
+ MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
+ PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
+ PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
+ BOOL symGetLineFromAddr64 (HANDLE hProcess, DWORD64 dwAddr,
+ PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line);
+
+ // Print one liner describing state (if library loaded, which functions are
+ // missing - if any, and the dbhelp API version)
+ void print_state_on(outputStream* st);
+
+};
+
+
+#endif // OS_WINDOWS_VM_DBGHELPLOADER_HPP
+
--- a/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os_cpu/aix_ppc/vm/atomic_aix_ppc.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -106,8 +106,8 @@
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(4 == sizeof(I));
- STATIC_CAST(4 == sizeof(D));
+ STATIC_ASSERT(4 == sizeof(I));
+ STATIC_ASSERT(4 == sizeof(D));
D result;
@@ -129,8 +129,8 @@
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(8 == sizeof(I));
- STATIC_CAST(8 == sizeof(D));
+ STATIC_ASSERT(8 == sizeof(I));
+ STATIC_ASSERT(8 == sizeof(D));
D result;
--- a/hotspot/src/os_cpu/aix_ppc/vm/thread_aix_ppc.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os_cpu/aix_ppc/vm/thread_aix_ppc.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -29,7 +29,6 @@
private:
void pd_initialize() {
_anchor.clear();
- _last_interpreter_fp = NULL;
}
// The `last' frame is the youngest Java frame on the thread's stack.
@@ -60,20 +59,4 @@
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext,
bool isInJava);
- // -Xprof support
- //
- // In order to find the last Java fp from an async profile
- // tick, we store the current interpreter fp in the thread.
- // This value is only valid while we are in the C++ interpreter
- // and profiling.
- protected:
- intptr_t *_last_interpreter_fp;
-
- public:
- static ByteSize last_interpreter_fp_offset() {
- return byte_offset_of(JavaThread, _last_interpreter_fp);
- }
-
- intptr_t* last_interpreter_fp() { return _last_interpreter_fp; }
-
#endif // OS_CPU_AIX_PPC_VM_THREAD_AIX_PPC_HPP
--- a/hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os_cpu/bsd_zero/vm/atomic_bsd_zero.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -184,8 +184,8 @@
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(4 == sizeof(I));
- STATIC_CAST(4 == sizeof(D));
+ STATIC_ASSERT(4 == sizeof(I));
+ STATIC_ASSERT(4 == sizeof(D));
#ifdef ARM
return add_using_helper<int>(arm_add_and_fetch, add_value, dest);
@@ -201,8 +201,8 @@
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(8 == sizeof(I));
- STATIC_CAST(8 == sizeof(D));
+ STATIC_ASSERT(8 == sizeof(I));
+ STATIC_ASSERT(8 == sizeof(D));
return __sync_add_and_fetch(dest, add_value);
}
@@ -283,7 +283,7 @@
T volatile* dest,
T compare_value,
cmpxchg_memory_order order) const {
- STATIC_CAST(4 == sizeof(T));
+ STATIC_ASSERT(4 == sizeof(T));
#ifdef ARM
return cmpxchg_using_helper<int>(arm_compare_and_swap, exchange_value, dest, compare_value);
#else
@@ -301,7 +301,7 @@
T volatile* dest,
T compare_value,
cmpxchg_memory_order order) const {
- STATIC_CAST(8 == sizeof(T));
+ STATIC_ASSERT(8 == sizeof(T));
return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
}
--- a/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os_cpu/linux_ppc/vm/atomic_linux_ppc.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -104,8 +104,8 @@
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(4 == sizeof(I));
- STATIC_CAST(4 == sizeof(D));
+ STATIC_ASSERT(4 == sizeof(I));
+ STATIC_ASSERT(4 == sizeof(D));
D result;
@@ -127,8 +127,8 @@
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(8 == sizeof(I));
- STATIC_CAST(8 == sizeof(D));
+ STATIC_ASSERT(8 == sizeof(I));
+ STATIC_ASSERT(8 == sizeof(D));
D result;
--- a/hotspot/src/os_cpu/linux_ppc/vm/thread_linux_ppc.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os_cpu/linux_ppc/vm/thread_linux_ppc.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -30,7 +30,6 @@
void pd_initialize() {
_anchor.clear();
- _last_interpreter_fp = NULL;
}
// The `last' frame is the youngest Java frame on the thread's stack.
@@ -62,22 +61,4 @@
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava);
- protected:
-
- // -Xprof support
- //
- // In order to find the last Java fp from an async profile
- // tick, we store the current interpreter fp in the thread.
- // This value is only valid while we are in the C++ interpreter
- // and profiling.
- intptr_t *_last_interpreter_fp;
-
- public:
-
- static ByteSize last_interpreter_fp_offset() {
- return byte_offset_of(JavaThread, _last_interpreter_fp);
- }
-
- intptr_t* last_interpreter_fp() { return _last_interpreter_fp; }
-
#endif // OS_CPU_LINUX_PPC_VM_THREAD_LINUX_PPC_HPP
--- a/hotspot/src/os_cpu/linux_s390/vm/atomic_linux_s390.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os_cpu/linux_s390/vm/atomic_linux_s390.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -92,9 +92,9 @@
template<>
template<typename I, typename D>
-inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(4 == sizeof(I));
- STATIC_CAST(4 == sizeof(D));
+inline D Atomic::PlatformAdd<4>::add_and_fetch(I inc, D volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(I));
+ STATIC_ASSERT(4 == sizeof(D));
D old, upd;
@@ -143,9 +143,9 @@
template<>
template<typename I, typename D>
-inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(8 == sizeof(I));
- STATIC_CAST(8 == sizeof(D));
+inline D Atomic::PlatformAdd<8>::add_and_fetch(I inc, D volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(I));
+ STATIC_ASSERT(8 == sizeof(D));
D old, upd;
--- a/hotspot/src/os_cpu/linux_s390/vm/thread_linux_s390.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os_cpu/linux_s390/vm/thread_linux_s390.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -30,7 +30,6 @@
void pd_initialize() {
_anchor.clear();
- _last_interpreter_fp = NULL;
}
// The `last' frame is the youngest Java frame on the thread's stack.
@@ -61,22 +60,4 @@
bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, bool isInJava);
- protected:
-
- // -Xprof support
- //
- // In order to find the last Java fp from an async profile
- // tick, we store the current interpreter fp in the thread.
- // This value is only valid while we are in the C++ interpreter
- // and profiling.
- intptr_t *_last_interpreter_fp;
-
- public:
-
- static ByteSize last_interpreter_fp_offset() {
- return byte_offset_of(JavaThread, _last_interpreter_fp);
- }
-
- intptr_t* last_interpreter_fp() { return _last_interpreter_fp; }
-
#endif // OS_CPU_LINUX_S390_VM_THREAD_LINUX_S390_HPP
--- a/hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -62,8 +62,8 @@
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(4 == sizeof(I));
- STATIC_CAST(4 == sizeof(D));
+ STATIC_ASSERT(4 == sizeof(I));
+ STATIC_ASSERT(4 == sizeof(D));
D rv;
__asm__ volatile(
@@ -81,10 +81,11 @@
return rv;
}
+template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(8 == sizeof(I));
- STATIC_CAST(8 == sizeof(D));
+ STATIC_ASSERT(8 == sizeof(I));
+ STATIC_ASSERT(8 == sizeof(D));
D rv;
__asm__ volatile(
--- a/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os_cpu/linux_zero/vm/atomic_linux_zero.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -178,8 +178,8 @@
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(4 == sizeof(I));
- STATIC_CAST(4 == sizeof(D));
+ STATIC_ASSERT(4 == sizeof(I));
+ STATIC_ASSERT(4 == sizeof(D));
#ifdef ARM
return add_using_helper<int>(arm_add_and_fetch, add_value, dest);
@@ -195,8 +195,8 @@
template<>
template<typename I, typename D>
inline D Atomic::PlatformAdd<8>::add_and_fetch(I add_value, D volatile* dest) const {
- STATIC_CAST(8 == sizeof(I));
- STATIC_CAST(8 == sizeof(D));
+ STATIC_ASSERT(8 == sizeof(I));
+ STATIC_ASSERT(8 == sizeof(D));
return __sync_add_and_fetch(dest, add_value);
}
--- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -29,7 +29,6 @@
#include "classfile/vmSymbols.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
-#include "decoder_windows.hpp"
#include "interpreter/interpreter.hpp"
#include "jvm_windows.h"
#include "memory/allocation.inline.hpp"
@@ -51,10 +50,12 @@
#include "runtime/stubRoutines.hpp"
#include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp"
+#include "unwind_windows_x86.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
+#include "windbghelp.hpp"
-# include "unwind_windows_x86.hpp"
+
#undef REG_SP
#undef REG_FP
#undef REG_PC
@@ -401,24 +402,18 @@
lastpc = pc;
}
- PVOID p = WindowsDbgHelp::SymFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);
+ PVOID p = WindowsDbgHelp::symFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);
if (!p) {
// StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash.
break;
}
- BOOL result = WindowsDbgHelp::StackWalk64(
+ BOOL result = WindowsDbgHelp::stackWalk64(
IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType,
GetCurrentProcess(), // __in HANDLE hProcess,
GetCurrentThread(), // __in HANDLE hThread,
&stk, // __inout LP STACKFRAME64 StackFrame,
- &ctx, // __inout PVOID ContextRecord,
- NULL, // __in_opt PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
- WindowsDbgHelp::pfnSymFunctionTableAccess64(),
- // __in_opt PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
- WindowsDbgHelp::pfnSymGetModuleBase64(),
- // __in_opt PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
- NULL); // __in_opt PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
+ &ctx); // __inout PVOID ContextRecord,
if (!result) {
break;
--- a/hotspot/src/share/vm/Xusage.txt Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/Xusage.txt Sun Sep 03 14:19:45 2017 +0200
@@ -12,7 +12,6 @@
-Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size
-Xss<size> set java thread stack size
- -Xprof output cpu profiling data (deprecated)
-Xfuture enable strictest checks, anticipating future default
-Xrs reduce use of OS signals by Java/VM (see documentation)
-Xcheck:jni perform additional checks for JNI functions
--- a/hotspot/src/share/vm/aot/aotCodeHeap.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/aot/aotCodeHeap.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -478,6 +478,8 @@
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy", address, StubRoutines::_arrayof_oop_disjoint_arraycopy);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_arrayof_oop_disjoint_arraycopy_uninit", address, StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_unsafe_arraycopy", address, StubRoutines::_unsafe_arraycopy);
+
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_checkcast_arraycopy", address, StubRoutines::_checkcast_arraycopy);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_encryptBlock", address, StubRoutines::_aescrypt_encryptBlock);
--- a/hotspot/src/share/vm/classfile/classLoader.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -57,7 +57,6 @@
#include "prims/jvm_misc.hpp"
#include "runtime/arguments.hpp"
#include "runtime/compilationPolicy.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/handles.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
@@ -147,6 +146,7 @@
ClassPathEntry* ClassLoader::_first_append_entry = NULL;
ClassPathEntry* ClassLoader::_last_append_entry = NULL;
int ClassLoader::_num_entries = 0;
+int ClassLoader::_num_boot_entries = -1;
#if INCLUDE_CDS
GrowableArray<char*>* ClassLoader::_boot_modules_array = NULL;
GrowableArray<char*>* ClassLoader::_platform_modules_array = NULL;
@@ -242,7 +242,7 @@
// Given a fully qualified class name, find its defining package in the class loader's
// package entry table.
-static PackageEntry* get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS) {
+PackageEntry* ClassLoader::get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS) {
ResourceMark rm(THREAD);
const char *pkg_name = ClassLoader::package_from_name(class_name);
if (pkg_name == NULL) {
@@ -509,7 +509,7 @@
#endif
} else {
- PackageEntry* package_entry = get_package_entry(name, ClassLoaderData::the_null_class_loader_data(), CHECK_NULL);
+ PackageEntry* package_entry = ClassLoader::get_package_entry(name, ClassLoaderData::the_null_class_loader_data(), CHECK_NULL);
if (package_entry != NULL) {
ResourceMark rm;
// Get the module name
@@ -540,6 +540,13 @@
return NULL;
}
+JImageLocationRef ClassLoader::jimage_find_resource(JImageFile* jf,
+ const char* module_name,
+ const char* file_name,
+ jlong &size) {
+ return ((*JImageFindResource)(jf, module_name, get_jimage_version_string(), file_name, &size));
+}
+
#ifndef PRODUCT
bool ctw_visitor(JImageFile* jimage,
const char* module_name, const char* version, const char* package,
@@ -1066,7 +1073,7 @@
char path[JVM_MAXPATHLEN];
char ebuf[1024];
void* handle = NULL;
- if (os::dll_build_name(path, sizeof(path), Arguments::get_dll_dir(), "zip")) {
+ if (os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), "zip")) {
handle = os::dll_load(path, ebuf, sizeof ebuf);
}
if (handle == NULL) {
@@ -1104,7 +1111,7 @@
char path[JVM_MAXPATHLEN];
char ebuf[1024];
void* handle = NULL;
- if (os::dll_build_name(path, sizeof(path), Arguments::get_dll_dir(), "jimage")) {
+ if (os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), "jimage")) {
handle = os::dll_load(path, ebuf, sizeof ebuf);
}
if (handle == NULL) {
@@ -1434,7 +1441,6 @@
const char* const class_name = name->as_C_string();
EventMark m("loading class %s", class_name);
- ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);
const char* const file_name = file_name_for_class_name(class_name,
name->utf8_length());
@@ -1459,9 +1465,6 @@
// This would include:
// [--patch-module=<module>=<file>(<pathsep><file>)*]; [jimage | exploded module build]
//
- // DumpSharedSpaces and search_append_only are mutually exclusive and cannot
- // be true at the same time.
- assert(!(DumpSharedSpaces && search_append_only), "DumpSharedSpaces and search_append_only are both true");
// Load Attempt #1: --patch-module
// Determine the class' defining module. If it appears in the _patch_mod_entries,
@@ -1507,6 +1510,11 @@
e = _first_append_entry;
while (e != NULL) {
+ if (DumpSharedSpaces && classpath_index >= _num_boot_entries) {
+ // Do not load any class from the app classpath using the boot loader. Let
+ // the built-in app class laoder load them.
+ break;
+ }
stream = e->open_stream(file_name, CHECK_NULL);
if (!context.check(stream, classpath_index)) {
return NULL;
@@ -1520,9 +1528,6 @@
}
if (NULL == stream) {
- if (DumpSharedSpaces) {
- tty->print_cr("Preload Warning: Cannot find %s", class_name);
- }
return NULL;
}
@@ -1548,6 +1553,100 @@
return context.record_result(name, e, classpath_index, result, THREAD);
}
+#if INCLUDE_CDS
+static char* skip_uri_protocol(char* source) {
+ if (strncmp(source, "file:", 5) == 0) {
+ // file: protocol path could start with file:/ or file:///
+ // locate the char after all the forward slashes
+ int offset = 5;
+ while (*(source + offset) == '/') {
+ offset++;
+ }
+ source += offset;
+ // for non-windows platforms, move back one char as the path begins with a '/'
+#ifndef _WINDOWS
+ source -= 1;
+#endif
+ } else if (strncmp(source, "jrt:/", 5) == 0) {
+ source += 5;
+ }
+ return source;
+}
+
+void ClassLoader::record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream) {
+ assert(DumpSharedSpaces, "sanity");
+ assert(stream != NULL, "sanity");
+
+ if (ik->is_anonymous()) {
+ // We do not archive anonymous classes.
+ return;
+ }
+
+ if (stream->source() == NULL) {
+ if (ik->class_loader() == NULL) {
+ // JFR classes
+ ik->set_shared_classpath_index(0);
+ ik->set_class_loader_type(ClassLoader::BOOT_LOADER);
+ }
+ return;
+ }
+
+ assert(has_jrt_entry(), "CDS dumping does not support exploded JDK build");
+
+ ModuleEntry* module = ik->module();
+ ClassPathEntry* e = NULL;
+ int classpath_index = 0;
+
+ // Check if the class is from the runtime image
+ if (module != NULL && (module->location() != NULL) &&
+ (module->location()->starts_with("jrt:"))) {
+ e = _jrt_entry;
+ classpath_index = 0;
+ } else {
+ classpath_index = 1;
+ ResourceMark rm;
+ char* canonical_path = NEW_RESOURCE_ARRAY(char, JVM_MAXPATHLEN);
+ for (e = _first_append_entry; e != NULL; e = e->next()) {
+ if (get_canonical_path(e->name(), canonical_path, JVM_MAXPATHLEN)) {
+ char* src = (char*)stream->source();
+ // save the path from the file: protocol or the module name from the jrt: protocol
+ // if no protocol prefix is found, src is the same as stream->source() after the following call
+ src = skip_uri_protocol(src);
+ if (strcmp(canonical_path, os::native_path((char*)src)) == 0) {
+ break;
+ }
+ classpath_index ++;
+ }
+ }
+ if (e == NULL) {
+ assert(ik->shared_classpath_index() < 0,
+ "must be a class from a custom jar which isn't in the class path or boot class path");
+ return;
+ }
+ }
+
+ if (classpath_index < _num_boot_entries) {
+ // ik is either:
+ // 1) a boot class loaded from the runtime image during vm initialization (classpath_index = 0); or
+ // 2) a user's class from -Xbootclasspath/a (classpath_index > 0)
+ // In the second case, the classpath_index, classloader_type will be recorded via
+ // context.record_result() in ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS).
+ if (classpath_index > 0) {
+ return;
+ }
+ }
+
+ ResourceMark rm;
+ const char* const class_name = ik->name()->as_C_string();
+ const char* const file_name = file_name_for_class_name(class_name,
+ ik->name()->utf8_length());
+ assert(file_name != NULL, "invariant");
+ Thread* THREAD = Thread::current();
+ ClassLoaderExt::Context context(class_name, file_name, CATCH);
+ context.record_result(ik->name(), e, classpath_index, ik, THREAD);
+}
+#endif // INCLUDE_CDS
+
// Initialize the class loader's access to methods in libzip. Parse and
// process the boot classpath into a list ClassPathEntry objects. Once
// this list has been created, it must not change order (see class PackageInfo)
@@ -1632,6 +1731,7 @@
#if INCLUDE_CDS
void ClassLoader::initialize_shared_path() {
if (DumpSharedSpaces) {
+ _num_boot_entries = _num_entries;
ClassLoaderExt::setup_search_paths();
_shared_paths_misc_info->write_jint(0); // see comments in SharedPathsMiscInfo::check()
}
--- a/hotspot/src/share/vm/classfile/classLoader.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/classLoader.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -25,6 +25,7 @@
#ifndef SHARE_VM_CLASSFILE_CLASSLOADER_HPP
#define SHARE_VM_CLASSFILE_CLASSLOADER_HPP
+#include "classfile/jimage.hpp"
#include "runtime/orderAccess.hpp"
#include "runtime/perfData.hpp"
#include "utilities/exceptions.hpp"
@@ -47,6 +48,7 @@
class JImageFile;
class ClassFileStream;
+class PackageEntry;
class ClassPathEntry : public CHeapObj<mtClass> {
private:
@@ -103,7 +105,6 @@
jlong pos; /* position of LOC header (if negative) or data */
} jzentry;
-
class ClassPathZipEntry: public ClassPathEntry {
enum {
_unknown = 0,
@@ -249,6 +250,10 @@
// the entries on the _first_append_entry linked list.
static int _num_entries;
+ // number of entries in the boot class path including the
+ // java runtime image
+ static int _num_boot_entries;
+
// Array of module names associated with the boot class loader
CDS_ONLY(static GrowableArray<char*>* _boot_modules_array;)
@@ -289,6 +294,7 @@
static bool get_canonical_path(const char* orig, char* out, int len);
static const char* file_name_for_class_name(const char* class_name,
int class_name_len);
+ static PackageEntry* get_package_entry(const char* class_name, ClassLoaderData* loader_data, TRAPS);
public:
static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg);
@@ -436,7 +442,10 @@
static void initialize_module_loader_map(JImageFile* jimage);
static s2 classloader_type(Symbol* class_name, ClassPathEntry* e,
int classpath_index, TRAPS);
+ static void record_shared_class_loader_type(InstanceKlass* ik, const ClassFileStream* stream);
#endif
+ static JImageLocationRef jimage_find_resource(JImageFile* jf, const char* module_name,
+ const char* file_name, jlong &size);
static void trace_class_path(const char* msg, const char* name = NULL);
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -75,6 +75,9 @@
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#endif // INCLUDE_ALL_GCS
#if INCLUDE_TRACE
#include "trace/tracing.hpp"
#endif
@@ -764,6 +767,25 @@
return OopHandle(_handles.add(h()));
}
+void ClassLoaderData::remove_handle(OopHandle h) {
+ oop* ptr = h.ptr_raw();
+ if (ptr != NULL) {
+ assert(_handles.contains(ptr), "Got unexpected handle " PTR_FORMAT, p2i(ptr));
+#if INCLUDE_ALL_GCS
+ // This barrier is used by G1 to remember the old oop values, so
+ // that we don't forget any objects that were live at the snapshot at
+ // the beginning.
+ if (UseG1GC) {
+ oop obj = *ptr;
+ if (obj != NULL) {
+ G1SATBCardTableModRefBS::enqueue(obj);
+ }
+ }
+#endif
+ *ptr = NULL;
+ }
+}
+
void ClassLoaderData::init_handle_locked(OopHandle& dest, Handle h) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
if (dest.resolve() != NULL) {
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -364,6 +364,7 @@
const char* loader_name();
OopHandle add_handle(Handle h);
+ void remove_handle(OopHandle h);
void init_handle_locked(OopHandle& pd, Handle h); // used for concurrent access to ModuleEntry::_pd field
void add_class(Klass* k, bool publicize = true);
void remove_class(Klass* k);
--- a/hotspot/src/share/vm/classfile/classLoaderExt.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -26,6 +26,7 @@
#define SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
#include "classfile/classLoader.hpp"
+#include "classfile/systemDictionary.hpp"
#include "oops/instanceKlass.hpp"
#include "runtime/handles.hpp"
@@ -56,8 +57,15 @@
if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) {
#if INCLUDE_CDS
if (DumpSharedSpaces) {
- s2 classloader_type = ClassLoader::classloader_type(
- class_name, e, classpath_index, CHECK_(result));
+ oop loader = result->class_loader();
+ s2 classloader_type = ClassLoader::BOOT_LOADER;
+ if (SystemDictionary::is_system_class_loader(loader)) {
+ classloader_type = ClassLoader::APP_LOADER;
+ ClassLoaderExt::set_has_app_classes();
+ } else if (SystemDictionary::is_platform_class_loader(loader)) {
+ classloader_type = ClassLoader::PLATFORM_LOADER;
+ ClassLoaderExt::set_has_platform_classes();
+ }
result->set_shared_classpath_index(classpath_index);
result->set_class_loader_type(classloader_type);
}
@@ -82,6 +90,13 @@
return true;
}
static Klass* load_one_class(ClassListParser* parser, TRAPS);
+#if INCLUDE_CDS
+ static void set_has_app_classes() {}
+ static void set_has_platform_classes() {}
+ static char* read_manifest(ClassPathEntry* entry, jint *manifest_size, TRAPS) {
+ return NULL;
+ }
+#endif
};
#endif // SHARE_VM_CLASSFILE_CLASSLOADEREXT_HPP
--- a/hotspot/src/share/vm/classfile/dictionary.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/dictionary.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -85,6 +85,7 @@
void Dictionary::free_entry(DictionaryEntry* entry) {
// avoid recursion when deleting linked list
+ // pd_set is accessed during a safepoint.
while (entry->pd_set() != NULL) {
ProtectionDomainEntry* to_delete = entry->pd_set();
entry->set_pd_set(to_delete->next());
@@ -101,7 +102,7 @@
if (protection_domain == instance_klass()->protection_domain()) {
// Ensure this doesn't show up in the pd_set (invariant)
bool in_pd_set = false;
- for (ProtectionDomainEntry* current = _pd_set;
+ for (ProtectionDomainEntry* current = pd_set_acquire();
current != NULL;
current = current->next()) {
if (current->protection_domain() == protection_domain) {
@@ -121,7 +122,7 @@
return true;
}
- for (ProtectionDomainEntry* current = _pd_set;
+ for (ProtectionDomainEntry* current = pd_set_acquire();
current != NULL;
current = current->next()) {
if (current->protection_domain() == protection_domain) return true;
@@ -135,12 +136,12 @@
if (!contains_protection_domain(protection_domain())) {
ProtectionDomainCacheEntry* entry = SystemDictionary::cache_get(protection_domain);
ProtectionDomainEntry* new_head =
- new ProtectionDomainEntry(entry, _pd_set);
+ new ProtectionDomainEntry(entry, pd_set());
// Warning: Preserve store ordering. The SystemDictionary is read
// without locks. The new ProtectionDomainEntry must be
// complete before other threads can be allowed to see it
// via a store to _pd_set.
- OrderAccess::release_store_ptr(&_pd_set, new_head);
+ release_set_pd_set(new_head);
}
LogTarget(Trace, protectiondomain) lt;
if (lt.is_enabled()) {
@@ -365,11 +366,21 @@
for (int i = 0; i < table_size(); ++i) {
DictionaryEntry* p = bucket(i);
while (p != NULL) {
- DictionaryEntry* tmp;
- tmp = p->next();
- p->set_next(master_list);
- master_list = p;
- p = tmp;
+ DictionaryEntry* next = p->next();
+ InstanceKlass*ik = p->instance_klass();
+ // we cannot include signed classes in the archive because the certificates
+ // used during dump time may be different than those used during
+ // runtime (due to expiration, etc).
+ if (ik->signers() != NULL) {
+ ResourceMark rm;
+ tty->print_cr("Preload Warning: Skipping %s from signed JAR",
+ ik->name()->as_C_string());
+ free_entry(p);
+ } else {
+ p->set_next(master_list);
+ master_list = p;
+ }
+ p = next;
}
set_entry(i, NULL);
}
--- a/hotspot/src/share/vm/classfile/dictionary.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/dictionary.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -29,6 +29,7 @@
#include "classfile/systemDictionary.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/oop.hpp"
+#include "runtime/orderAccess.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/ostream.hpp"
@@ -48,21 +49,6 @@
DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name);
protected:
- DictionaryEntry* bucket(int i) const {
- return (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i);
- }
-
- // The following method is not MT-safe and must be done under lock.
- DictionaryEntry** bucket_addr(int i) {
- return (DictionaryEntry**)Hashtable<InstanceKlass*, mtClass>::bucket_addr(i);
- }
-
- void add_entry(int index, DictionaryEntry* new_entry) {
- Hashtable<InstanceKlass*, mtClass>::add_entry(index, (HashtableEntry<InstanceKlass*, mtClass>*)new_entry);
- }
-
- void free_entry(DictionaryEntry* entry);
-
static size_t entry_size();
public:
Dictionary(ClassLoaderData* loader_data, int table_size);
@@ -106,6 +92,24 @@
void print_on(outputStream* st) const;
void verify();
+ DictionaryEntry* bucket(int i) const {
+ return (DictionaryEntry*)Hashtable<InstanceKlass*, mtClass>::bucket(i);
+ }
+
+ // The following method is not MT-safe and must be done under lock.
+ DictionaryEntry** bucket_addr(int i) {
+ return (DictionaryEntry**)Hashtable<InstanceKlass*, mtClass>::bucket_addr(i);
+ }
+
+ void add_entry(int index, DictionaryEntry* new_entry) {
+ Hashtable<InstanceKlass*, mtClass>::add_entry(index, (HashtableEntry<InstanceKlass*, mtClass>*)new_entry);
+ }
+
+ void unlink_entry(DictionaryEntry* entry) {
+ Hashtable<InstanceKlass*, mtClass>::unlink_entry((HashtableEntry<InstanceKlass*, mtClass>*)entry);
+ }
+
+ void free_entry(DictionaryEntry* entry);
};
// An entry in the class loader data dictionaries, this describes a class as
@@ -134,7 +138,7 @@
// It is essentially a cache to avoid repeated Java up-calls to
// ClassLoader.checkPackageAccess().
//
- ProtectionDomainEntry* _pd_set;
+ ProtectionDomainEntry* volatile _pd_set;
public:
// Tells whether a protection is in the approved set.
@@ -153,8 +157,15 @@
return (DictionaryEntry**)HashtableEntry<InstanceKlass*, mtClass>::next_addr();
}
- ProtectionDomainEntry* pd_set() const { return _pd_set; }
- void set_pd_set(ProtectionDomainEntry* pd_set) { _pd_set = pd_set; }
+ ProtectionDomainEntry* pd_set() const { return _pd_set; }
+ void set_pd_set(ProtectionDomainEntry* new_head) { _pd_set = new_head; }
+
+ ProtectionDomainEntry* pd_set_acquire() const {
+ return (ProtectionDomainEntry*)OrderAccess::load_ptr_acquire(&_pd_set);
+ }
+ void release_set_pd_set(ProtectionDomainEntry* new_head) {
+ OrderAccess::release_store_ptr(&_pd_set, new_head);
+ }
// Tells whether the initiating class' protection domain can access the klass in this entry
bool is_valid_protection_domain(Handle protection_domain) {
@@ -167,7 +178,7 @@
}
void verify_protection_domain_set() {
- for (ProtectionDomainEntry* current = _pd_set;
+ for (ProtectionDomainEntry* current = pd_set(); // accessed at a safepoint
current != NULL;
current = current->_next) {
current->_pd_cache->protection_domain()->verify();
@@ -181,7 +192,7 @@
void print_count(outputStream *st) {
int count = 0;
- for (ProtectionDomainEntry* current = _pd_set;
+ for (ProtectionDomainEntry* current = pd_set(); // accessed inside SD lock
current != NULL;
current = current->_next) {
count++;
@@ -246,10 +257,6 @@
class SymbolPropertyTable : public Hashtable<Symbol*, mtSymbol> {
friend class VMStructs;
private:
- SymbolPropertyEntry* bucket(int i) {
- return (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::bucket(i);
- }
-
// The following method is not MT-safe and must be done under lock.
SymbolPropertyEntry** bucket_addr(int i) {
return (SymbolPropertyEntry**) Hashtable<Symbol*, mtSymbol>::bucket_addr(i);
@@ -303,5 +310,9 @@
void methods_do(void f(Method*));
void verify();
+
+ SymbolPropertyEntry* bucket(int i) {
+ return (SymbolPropertyEntry*) Hashtable<Symbol*, mtSymbol>::bucket(i);
+ }
};
#endif // SHARE_VM_CLASSFILE_DICTIONARY_HPP
--- a/hotspot/src/share/vm/classfile/klassFactory.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/klassFactory.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -70,11 +70,25 @@
ClassLoaderData* loader_data =
ClassLoaderData::class_loader_data(class_loader());
int path_index = ik->shared_classpath_index();
- SharedClassPathEntry* ent =
- (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+ const char* pathname;
+ if (path_index < 0) {
+ // shared classes loaded by user defined class loader
+ // do not have shared_classpath_index
+ ModuleEntry* mod_entry = ik->module();
+ if (mod_entry != NULL && (mod_entry->location() != NULL)) {
+ ResourceMark rm;
+ pathname = (const char*)(mod_entry->location()->as_C_string());
+ } else {
+ pathname = "";
+ }
+ } else {
+ SharedClassPathEntry* ent =
+ (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+ pathname = ent == NULL ? NULL : ent->name();
+ }
ClassFileStream* stream = new ClassFileStream(ptr,
end_ptr - ptr,
- ent == NULL ? NULL : ent->name(),
+ pathname,
ClassFileStream::verify);
ClassFileParser parser(stream,
class_name,
@@ -215,8 +229,10 @@
TRACE_KLASS_CREATION(result, parser, THREAD);
-#if INCLUDE_CDS && INCLUDE_JVMTI
+#if INCLUDE_CDS
if (DumpSharedSpaces) {
+ ClassLoader::record_shared_class_loader_type(result, stream);
+#if INCLUDE_JVMTI
assert(cached_class_file == NULL, "Sanity");
// Archive the class stream data into the optional data section
JvmtiCachedClassFileData *p;
@@ -233,8 +249,9 @@
p->length = len;
memcpy(p->data, bytes, len);
result->set_archived_class_data(p);
+#endif // INCLUDE_JVMTI
}
-#endif
+#endif // INCLUDE_CDS
return result;
}
--- a/hotspot/src/share/vm/classfile/stringTable.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -729,7 +729,6 @@
}
G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity());
- assert(string_space->length() <= 2, "sanity");
return true;
}
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -66,6 +66,7 @@
#include "prims/resolvedMethodTable.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
+#include "runtime/arguments_ext.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/fieldType.hpp"
#include "runtime/handles.inline.hpp"
@@ -869,7 +870,7 @@
// during compilations.
MutexLocker mu(Compile_lock, THREAD);
update_dictionary(d_index, d_hash, p_index, p_hash,
- k, class_loader, THREAD);
+ k, class_loader, THREAD);
}
if (JvmtiExport::should_post_class_load()) {
@@ -910,12 +911,9 @@
if (protection_domain() == NULL) return k;
// Check the protection domain has the right access
- {
- MutexLocker mu(SystemDictionary_lock, THREAD);
- if (dictionary->is_valid_protection_domain(d_index, d_hash, name,
- protection_domain)) {
- return k;
- }
+ if (dictionary->is_valid_protection_domain(d_index, d_hash, name,
+ protection_domain)) {
+ return k;
}
// Verify protection domain. If it fails an exception is thrown
@@ -1009,7 +1007,6 @@
// Create a new CLD for anonymous class, that uses the same class loader
// as the host_klass
guarantee(host_klass->class_loader() == class_loader(), "should be the same");
- guarantee(!DumpSharedSpaces, "must not create anonymous classes when dumping");
loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL);
} else {
loader_data = ClassLoaderData::class_loader_data(class_loader());
@@ -1078,6 +1075,15 @@
Handle protection_domain,
ClassFileStream* st,
TRAPS) {
+#if INCLUDE_CDS
+ ResourceMark rm(THREAD);
+ if (DumpSharedSpaces && !class_loader.is_null() &&
+ !ArgumentsExt::using_AppCDS() && strcmp(class_name->as_C_string(), "Unnamed") != 0) {
+ // If AppCDS is not enabled, don't define the class at dump time (except for the "Unnamed"
+ // class, which is used by MethodHandles).
+ THROW_MSG_NULL(vmSymbols::java_lang_ClassNotFoundException(), class_name->as_C_string());
+ }
+#endif
HandleMark hm(THREAD);
@@ -1104,11 +1110,13 @@
InstanceKlass* k = NULL;
#if INCLUDE_CDS
- k = SystemDictionaryShared::lookup_from_stream(class_name,
- class_loader,
- protection_domain,
- st,
- CHECK_NULL);
+ if (!DumpSharedSpaces) {
+ k = SystemDictionaryShared::lookup_from_stream(class_name,
+ class_loader,
+ protection_domain,
+ st,
+ CHECK_NULL);
+ }
#endif
if (k == NULL) {
@@ -1217,6 +1225,16 @@
"Cannot use sharing if java.base is patched");
ResourceMark rm;
int path_index = ik->shared_classpath_index();
+ ClassLoaderData* loader_data = class_loader_data(class_loader);
+ if (path_index < 0) {
+ // path_index < 0 indicates that the class is intended for a custom loader
+ // and should not be loaded by boot/platform/app loaders
+ if (loader_data->is_builtin_class_loader_data()) {
+ return false;
+ } else {
+ return true;
+ }
+ }
SharedClassPathEntry* ent =
(SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
if (!Universe::is_module_initialized()) {
@@ -1230,7 +1248,6 @@
PackageEntry* pkg_entry = NULL;
ModuleEntry* mod_entry = NULL;
const char* pkg_string = NULL;
- ClassLoaderData* loader_data = class_loader_data(class_loader);
pkg_name = InstanceKlass::package_from_name(class_name, CHECK_false);
if (pkg_name != NULL) {
pkg_string = pkg_name->as_C_string();
@@ -1403,6 +1420,18 @@
}
return ik;
}
+
+void SystemDictionary::clear_invoke_method_table() {
+ SymbolPropertyEntry* spe = NULL;
+ for (int index = 0; index < _invoke_method_table->table_size(); index++) {
+ SymbolPropertyEntry* p = _invoke_method_table->bucket(index);
+ while (p != NULL) {
+ spe = p;
+ p = p->next();
+ _invoke_method_table->free_entry(spe);
+ }
+ }
+}
#endif // INCLUDE_CDS
InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
@@ -1449,7 +1478,6 @@
}
}
} else {
- assert(!DumpSharedSpaces, "Archive dumped after module system initialization");
// After the module system has been initialized, check if the class'
// package is in a module defined to the boot loader.
if (pkg_name == NULL || pkg_entry == NULL || pkg_entry->in_unnamed_module()) {
@@ -1968,8 +1996,19 @@
invoke_method_table()->methods_do(f);
}
+class RemoveClassesClosure : public CLDClosure {
+ public:
+ void do_cld(ClassLoaderData* cld) {
+ if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
+ cld->dictionary()->remove_classes_in_error_state();
+ }
+ }
+};
+
void SystemDictionary::remove_classes_in_error_state() {
ClassLoaderData::the_null_class_loader_data()->dictionary()->remove_classes_in_error_state();
+ RemoveClassesClosure rcc;
+ ClassLoaderDataGraph::cld_do(&rcc);
}
// ----------------------------------------------------------------------------
@@ -2910,6 +2949,56 @@
}
}
+class CombineDictionariesClosure : public CLDClosure {
+ private:
+ Dictionary* _master_dictionary;
+ public:
+ CombineDictionariesClosure(Dictionary* master_dictionary) :
+ _master_dictionary(master_dictionary) {}
+ void do_cld(ClassLoaderData* cld) {
+ ResourceMark rm;
+ if (cld->is_system_class_loader_data() || cld->is_platform_class_loader_data()) {
+ for (int i = 0; i < cld->dictionary()->table_size(); ++i) {
+ Dictionary* curr_dictionary = cld->dictionary();
+ DictionaryEntry* p = curr_dictionary->bucket(i);
+ while (p != NULL) {
+ Symbol* name = p->instance_klass()->name();
+ unsigned int d_hash = _master_dictionary->compute_hash(name);
+ int d_index = _master_dictionary->hash_to_index(d_hash);
+ DictionaryEntry* next = p->next();
+ if (p->literal()->class_loader_data() != cld) {
+ // This is an initiating class loader entry; don't use it
+ log_trace(cds)("Skipping initiating cl entry: %s", name->as_C_string());
+ curr_dictionary->free_entry(p);
+ } else {
+ log_trace(cds)("Moved to boot dictionary: %s", name->as_C_string());
+ curr_dictionary->unlink_entry(p);
+ p->set_pd_set(NULL); // pd_set is runtime only information and will be reconstructed.
+ _master_dictionary->add_entry(d_index, p);
+ }
+ p = next;
+ }
+ *curr_dictionary->bucket_addr(i) = NULL;
+ }
+ }
+ }
+};
+
+// Combining platform and system loader dictionaries into boot loader dictionaries.
+// During run time, we only have one shared dictionary.
+void SystemDictionary::combine_shared_dictionaries() {
+ assert(DumpSharedSpaces, "dump time only");
+ Dictionary* master_dictionary = ClassLoaderData::the_null_class_loader_data()->dictionary();
+ CombineDictionariesClosure cdc(master_dictionary);
+ ClassLoaderDataGraph::cld_do(&cdc);
+
+ // These tables are no longer valid or necessary. Keeping them around will
+ // cause SystemDictionary::verify() to fail. Let's empty them.
+ _placeholders = new PlaceholderTable(_placeholder_table_size);
+ _loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
+
+ NOT_PRODUCT(SystemDictionary::verify());
+}
// caller needs ResourceMark
const char* SystemDictionary::loader_name(const oop loader) {
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -385,6 +385,7 @@
public:
// Sharing support.
static void reorder_dictionary_for_sharing();
+ static void combine_shared_dictionaries();
static size_t count_bytes_for_buckets();
static size_t count_bytes_for_table();
static void copy_buckets(char* top, char* end);
@@ -643,6 +644,7 @@
TRAPS);
static bool is_system_class_loader(oop class_loader);
static bool is_platform_class_loader(oop class_loader);
+ static void clear_invoke_method_table();
protected:
static InstanceKlass* find_shared_class(Symbol* class_name);
--- a/hotspot/src/share/vm/code/nmethod.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/code/nmethod.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1220,7 +1220,7 @@
// for stack scanning.
if (state == not_entrant) {
mark_as_seen_on_stack();
- OrderAccess::storestore();
+ OrderAccess::storestore(); // _stack_traversal_mark and _state
}
// Change state
--- a/hotspot/src/share/vm/code/nmethod.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/code/nmethod.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -136,7 +136,7 @@
// stack. An not_entrant method can be removed when there are no
// more activations, i.e., when the _stack_traversal_mark is less than
// current sweep traversal index.
- volatile jlong _stack_traversal_mark;
+ volatile long _stack_traversal_mark;
// The _hotness_counter indicates the hotness of a method. The higher
// the value the hotter the method. The hotness counter of a nmethod is
@@ -396,8 +396,8 @@
public:
// Sweeper support
- jlong stack_traversal_mark() { return OrderAccess::load_acquire(&_stack_traversal_mark); }
- void set_stack_traversal_mark(jlong l) { OrderAccess::release_store(&_stack_traversal_mark, l); }
+ long stack_traversal_mark() { return _stack_traversal_mark; }
+ void set_stack_traversal_mark(long l) { _stack_traversal_mark = l; }
// implicit exceptions support
address continuation_for_implicit_exception(address pc);
--- a/hotspot/src/share/vm/compiler/disassembler.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/compiler/disassembler.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,6 @@
#include "gc/shared/collectedHeap.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/stubCodeGenerator.hpp"
@@ -163,7 +162,6 @@
bool _print_pc;
bool _print_bytes;
address _cur_insn;
- int _total_ticks;
int _bytes_per_line; // arch-specific formatting option
static bool match(const char* event, const char* tag) {
@@ -213,18 +211,6 @@
_nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
// this calls reloc_string_for which calls oop::print_value_on
}
-
- // Output pc bucket ticks if we have any
- if (total_ticks() != 0) {
- address bucket_pc = FlatProfiler::bucket_start_for(pc);
- if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) {
- int bucket_count = FlatProfiler::bucket_count_for(pc0);
- if (bucket_count != 0) {
- st->bol();
- st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count);
- }
- }
- }
// follow each complete insn by a nice newline
st->cr();
}
@@ -233,8 +219,6 @@
outputStream* output() { return _output; }
address cur_insn() { return _cur_insn; }
- int total_ticks() { return _total_ticks; }
- void set_total_ticks(int n) { _total_ticks = n; }
const char* options() { return _option_buf; }
};
@@ -561,20 +545,6 @@
#endif
env.output()->print_cr(" [" PTR_FORMAT ", " PTR_FORMAT "] " JLONG_FORMAT " bytes", p2i(p), p2i(end), ((jlong)(end - p)));
- // If there has been profiling, print the buckets.
- if (FlatProfiler::bucket_start_for(p) != NULL) {
- unsigned char* p1 = p;
- int total_bucket_count = 0;
- while (p1 < end) {
- unsigned char* p0 = p1;
- p1 += pd_instruction_alignment();
- address bucket_pc = FlatProfiler::bucket_start_for(p1);
- if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
- total_bucket_count += FlatProfiler::bucket_count_for(p0);
- }
- env.set_total_ticks(total_bucket_count);
- }
-
// Print constant table.
if (nm->consts_size() > 0) {
nm->print_nmethod_labels(env.output(), nm->consts_begin());
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1719,7 +1719,6 @@
G1BlockOffsetTable::compute_size(g1_rs.size() / HeapWordSize),
G1BlockOffsetTable::heap_map_factor());
- ReservedSpace cardtable_rs(G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize));
G1RegionToSpaceMapper* cardtable_storage =
create_aux_memory_mapper("Card Table",
G1SATBCardTableLoggingModRefBS::compute_size(g1_rs.size() / HeapWordSize),
--- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -54,7 +54,6 @@
_gc_par_phases[UniverseRoots] = new WorkerDataArray<double>(max_gc_threads, "Universe Roots (ms):");
_gc_par_phases[JNIRoots] = new WorkerDataArray<double>(max_gc_threads, "JNI Handles Roots (ms):");
_gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray<double>(max_gc_threads, "ObjectSynchronizer Roots (ms):");
- _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray<double>(max_gc_threads, "FlatProfiler Roots (ms):");
_gc_par_phases[ManagementRoots] = new WorkerDataArray<double>(max_gc_threads, "Management Roots (ms):");
_gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray<double>(max_gc_threads, "SystemDictionary Roots (ms):");
_gc_par_phases[CLDGRoots] = new WorkerDataArray<double>(max_gc_threads, "CLDG Roots (ms):");
--- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -49,7 +49,6 @@
UniverseRoots,
JNIRoots,
ObjectSynchronizerRoots,
- FlatProfilerRoots,
ManagementRoots,
SystemDictionaryRoots,
CLDGRoots,
--- a/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1HeapVerifier.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -62,7 +62,7 @@
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (_g1h->is_obj_dead_cond(obj, _vo)) {
Log(gc, verify) log;
- log.info("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj));
+ log.error("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj));
if (_vo == VerifyOption_G1UseMarkWord) {
log.error(" Mark word: " PTR_FORMAT, p2i(obj->mark()));
}
--- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -48,7 +48,6 @@
#include "prims/jvmtiExport.hpp"
#include "runtime/atomic.hpp"
#include "runtime/biasedLocking.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.hpp"
#include "runtime/vmThread.hpp"
--- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -38,7 +38,6 @@
#include "gc/g1/g1RootProcessor.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "memory/allocation.inline.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/mutex.hpp"
#include "services/management.hpp"
#include "utilities/macros.hpp"
@@ -272,13 +271,6 @@
}
{
- G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::FlatProfilerRoots, worker_i);
- if (!_process_strong_tasks.is_task_claimed(G1RP_PS_FlatProfiler_oops_do)) {
- FlatProfiler::oops_do(strong_roots);
- }
- }
-
- {
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ManagementRoots, worker_i);
if (!_process_strong_tasks.is_task_claimed(G1RP_PS_Management_oops_do)) {
Management::oops_do(strong_roots);
--- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -57,7 +57,6 @@
G1RP_PS_Universe_oops_do,
G1RP_PS_JNIHandles_oops_do,
G1RP_PS_ObjectSynchronizer_oops_do,
- G1RP_PS_FlatProfiler_oops_do,
G1RP_PS_Management_oops_do,
G1RP_PS_SystemDictionary_oops_do,
G1RP_PS_ClassLoaderDataGraph_oops_do,
--- a/hotspot/src/share/vm/gc/parallel/pcTasks.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/parallel/pcTasks.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, 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
@@ -39,7 +39,6 @@
#include "oops/objArrayKlass.inline.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/thread.hpp"
#include "runtime/vmThread.hpp"
@@ -105,10 +104,6 @@
ObjectSynchronizer::oops_do(&mark_and_push_closure);
break;
- case flat_profiler:
- FlatProfiler::oops_do(&mark_and_push_closure);
- break;
-
case management:
Management::oops_do(&mark_and_push_closure);
break;
--- a/hotspot/src/share/vm/gc/parallel/pcTasks.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/parallel/pcTasks.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -94,12 +94,11 @@
jni_handles = 2,
threads = 3,
object_synchronizer = 4,
- flat_profiler = 5,
- management = 6,
- jvmti = 7,
- system_dictionary = 8,
- class_loader_data = 9,
- code_cache = 10
+ management = 5,
+ jvmti = 6,
+ system_dictionary = 7,
+ class_loader_data = 8,
+ code_cache = 9
};
private:
RootType _root_type;
--- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -50,7 +50,6 @@
#include "logging/log.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/biasedLocking.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/vmThread.hpp"
#include "services/management.hpp"
@@ -514,7 +513,6 @@
MarkingCodeBlobClosure each_active_code_blob(mark_and_push_closure(), !CodeBlobToOopClosure::FixRelocations);
Threads::oops_do(mark_and_push_closure(), &each_active_code_blob);
ObjectSynchronizer::oops_do(mark_and_push_closure());
- FlatProfiler::oops_do(mark_and_push_closure());
Management::oops_do(mark_and_push_closure());
JvmtiExport::oops_do(mark_and_push_closure());
SystemDictionary::always_strong_oops_do(mark_and_push_closure());
@@ -607,7 +605,6 @@
JNIHandles::oops_do(adjust_pointer_closure()); // Global (strong) JNI handles
Threads::oops_do(adjust_pointer_closure(), NULL);
ObjectSynchronizer::oops_do(adjust_pointer_closure());
- FlatProfiler::oops_do(adjust_pointer_closure());
Management::oops_do(adjust_pointer_closure());
JvmtiExport::oops_do(adjust_pointer_closure());
SystemDictionary::oops_do(adjust_pointer_closure());
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -60,7 +60,6 @@
#include "oops/objArrayKlass.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/vmThread.hpp"
#include "services/management.hpp"
@@ -2086,7 +2085,6 @@
// We scan the thread roots in parallel
Threads::create_thread_roots_marking_tasks(q);
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::object_synchronizer));
- q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::flat_profiler));
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::management));
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::system_dictionary));
q->enqueue(new MarkFromRootsTask(MarkFromRootsTask::class_loader_data));
@@ -2169,7 +2167,6 @@
JNIHandles::oops_do(&oop_closure); // Global (strong) JNI handles
Threads::oops_do(&oop_closure, NULL);
ObjectSynchronizer::oops_do(&oop_closure);
- FlatProfiler::oops_do(&oop_closure);
Management::oops_do(&oop_closure);
JvmtiExport::oops_do(&oop_closure);
SystemDictionary::oops_do(&oop_closure);
--- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -49,7 +49,6 @@
#include "logging/log.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/biasedLocking.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/vmThread.hpp"
@@ -381,7 +380,6 @@
// We scan the thread roots in parallel
Threads::create_thread_roots_tasks(q);
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::object_synchronizer));
- q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::flat_profiler));
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::management));
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::system_dictionary));
q->enqueue(new ScavengeRootsTask(ScavengeRootsTask::class_loader_data));
--- a/hotspot/src/share/vm/gc/parallel/psTasks.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/parallel/psTasks.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, 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
@@ -38,7 +38,6 @@
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/oop.inline.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/thread.hpp"
#include "runtime/vmThread.hpp"
#include "services/management.hpp"
@@ -74,10 +73,6 @@
ObjectSynchronizer::oops_do(&roots_closure);
break;
- case flat_profiler:
- FlatProfiler::oops_do(&roots_closure);
- break;
-
case system_dictionary:
SystemDictionary::oops_do(&roots_closure);
break;
--- a/hotspot/src/share/vm/gc/parallel/psTasks.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/parallel/psTasks.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, 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
@@ -57,12 +57,11 @@
jni_handles = 2,
threads = 3,
object_synchronizer = 4,
- flat_profiler = 5,
- system_dictionary = 6,
- class_loader_data = 7,
- management = 8,
- jvmti = 9,
- code_cache = 10
+ system_dictionary = 5,
+ class_loader_data = 6,
+ management = 7,
+ jvmti = 8,
+ code_cache = 9
};
private:
RootType _root_type;
--- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -46,7 +46,6 @@
#include "oops/instanceRefKlass.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/thread.inline.hpp"
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -47,7 +47,6 @@
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/biasedLocking.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/handles.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
@@ -71,7 +70,6 @@
GCH_PS_Universe_oops_do,
GCH_PS_JNIHandles_oops_do,
GCH_PS_ObjectSynchronizer_oops_do,
- GCH_PS_FlatProfiler_oops_do,
GCH_PS_Management_oops_do,
GCH_PS_SystemDictionary_oops_do,
GCH_PS_ClassLoaderDataGraph_oops_do,
@@ -606,9 +604,6 @@
if (!_process_strong_tasks->is_task_claimed(GCH_PS_ObjectSynchronizer_oops_do)) {
ObjectSynchronizer::oops_do(strong_roots);
}
- if (!_process_strong_tasks->is_task_claimed(GCH_PS_FlatProfiler_oops_do)) {
- FlatProfiler::oops_do(strong_roots);
- }
if (!_process_strong_tasks->is_task_claimed(GCH_PS_Management_oops_do)) {
Management::oops_do(strong_roots);
}
--- a/hotspot/src/share/vm/interpreter/rewriter.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/interpreter/rewriter.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -109,6 +109,11 @@
MetadataFactory::free_metadata(loader_data, cache);
_pool->set_cache(NULL); // so the verifier isn't confused
}
+
+ DEBUG_ONLY(
+ if (DumpSharedSpaces) {
+ cache->verify_just_initialized();
+ })
}
--- a/hotspot/src/share/vm/logging/logTag.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/logging/logTag.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -140,6 +140,7 @@
LOG_TAG(timer) \
LOG_TAG(update) \
LOG_TAG(unload) /* Trace unloading of classes */ \
+ LOG_TAG(unshareable) \
LOG_TAG(verification) \
LOG_TAG(verify) \
LOG_TAG(vmoperation) \
--- a/hotspot/src/share/vm/memory/metaspaceClosure.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/memory/metaspaceClosure.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -275,7 +275,8 @@
address, bool,
UniqueMetaspaceClosure::my_hash, // solaris compiler doesn't like: primitive_hash<address>
UniqueMetaspaceClosure::my_equals, // solaris compiler doesn't like: primitive_equals<address>
- 16384> _has_been_visited;
+ 15889, // prime number
+ ResourceObj::C_HEAP> _has_been_visited;
};
#endif // SHARE_VM_MEMORY_METASPACE_ITERATOR_HPP
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -374,25 +374,63 @@
// Global object for holding classes that have been loaded. Since this
// is run at a safepoint just before exit, this is the entire set of classes.
static GrowableArray<Klass*>* _global_klass_objects;
+
+static void collect_array_classes(Klass* k) {
+ _global_klass_objects->append_if_missing(k);
+ if (k->is_array_klass()) {
+ // Add in the array classes too
+ ArrayKlass* ak = ArrayKlass::cast(k);
+ Klass* h = ak->higher_dimension();
+ if (h != NULL) {
+ h->array_klasses_do(collect_array_classes);
+ }
+ }
+}
+
class CollectClassesClosure : public KlassClosure {
void do_klass(Klass* k) {
if (!(k->is_instance_klass() && InstanceKlass::cast(k)->is_in_error_state())) {
_global_klass_objects->append_if_missing(k);
}
+ if (k->is_array_klass()) {
+ // Add in the array classes too
+ ArrayKlass* ak = ArrayKlass::cast(k);
+ Klass* h = ak->higher_dimension();
+ if (h != NULL) {
+ h->array_klasses_do(collect_array_classes);
+ }
+ }
}
};
static void remove_unshareable_in_classes() {
for (int i = 0; i < _global_klass_objects->length(); i++) {
Klass* k = _global_klass_objects->at(i);
- k->remove_unshareable_info();
+ if (!k->is_objArray_klass()) {
+ // InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
+ // on their array classes.
+ assert(k->is_instance_klass() || k->is_typeArray_klass(), "must be");
+ k->remove_unshareable_info();
+ }
+ }
+}
+
+static void remove_java_mirror_in_classes() {
+ for (int i = 0; i < _global_klass_objects->length(); i++) {
+ Klass* k = _global_klass_objects->at(i);
+ if (!k->is_objArray_klass()) {
+ // InstanceKlass and TypeArrayKlass will in turn call remove_unshareable_info
+ // on their array classes.
+ assert(k->is_instance_klass() || k->is_typeArray_klass(), "must be");
+ k->remove_java_mirror();
+ }
}
}
static void rewrite_nofast_bytecode(Method* method) {
- RawBytecodeStream bcs(method);
+ BytecodeStream bcs(method);
while (!bcs.is_last_bytecode()) {
- Bytecodes::Code opcode = bcs.raw_next();
+ Bytecodes::Code opcode = bcs.next();
switch (opcode) {
case Bytecodes::_getfield: *bcs.bcp() = Bytecodes::_nofast_getfield; break;
case Bytecodes::_putfield: *bcs.bcp() = Bytecodes::_nofast_putfield; break;
@@ -446,6 +484,17 @@
}
}
+NOT_PRODUCT(
+static void assert_not_anonymous_class(InstanceKlass* k) {
+ assert(!(k->is_anonymous()), "cannot archive anonymous classes");
+}
+
+// Anonymous classes are not stored inside any dictionaries. They are created by
+// SystemDictionary::parse_stream() with a non-null host_klass.
+static void assert_no_anonymoys_classes_in_dictionaries() {
+ ClassLoaderDataGraph::dictionary_classes_do(assert_not_anonymous_class);
+})
+
// Objects of the Metadata types (such as Klass and ConstantPool) have C++ vtables.
// (In GCC this is the field <Type>::_vptr, i.e., first word in the object.)
//
@@ -957,8 +1006,8 @@
}
memcpy(p, obj, bytes);
bool isnew = _new_loc_table->put(obj, (address)p);
+ log_trace(cds)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(obj), p2i(p), bytes);
assert(isnew, "must be");
- log_trace(cds)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(obj), p2i(p), bytes);
_alloc_stats->record(ref->msotype(), int(newtop - oldtop), read_only);
if (ref->msotype() == MetaspaceObj::SymbolType) {
@@ -1151,6 +1200,9 @@
// Reorder the system dictionary. Moving the symbols affects
// how the hash table indices are calculated.
SystemDictionary::reorder_dictionary_for_sharing();
+ tty->print("Removing java_mirror ... ");
+ remove_java_mirror_in_classes();
+ tty->print_cr("done. ");
NOT_PRODUCT(SystemDictionary::verify();)
size_t buckets_bytes = SystemDictionary::count_bytes_for_buckets();
@@ -1218,11 +1270,20 @@
rewrite_nofast_bytecodes_and_calculate_fingerprints();
tty->print_cr("done. ");
+ // Move classes from platform/system dictionaries into the boot dictionary
+ SystemDictionary::combine_shared_dictionaries();
+
// Remove all references outside the metadata
tty->print("Removing unshareable information ... ");
remove_unshareable_in_classes();
tty->print_cr("done. ");
+ // We don't support archiving anonymous classes. Verify that they are not stored in
+ // the any dictionaries.
+ NOT_PRODUCT(assert_no_anonymoys_classes_in_dictionaries());
+
+ SystemDictionaryShared::finalize_verification_constraints();
+
ArchiveCompactor::initialize();
ArchiveCompactor::copy_and_compact();
@@ -1312,6 +1373,14 @@
ArchiveCompactor::alloc_stats()->print_stats(int(_ro_region.used()), int(_rw_region.used()),
int(_mc_region.used()), int(_md_region.used()));
}
+
+ if (PrintSystemDictionaryAtExit) {
+ SystemDictionary::print();
+ }
+ // There may be other pending VM operations that operate on the InstanceKlasses,
+ // which will fail because InstanceKlasses::remove_unshareable_info()
+ // has been called. Forget these operations and exit the VM directly.
+ vm_direct_exit(0);
}
void VM_PopulateDumpSharedSpace::print_region_stats() {
@@ -1438,10 +1507,6 @@
exit(1);
}
}
-
- // Copy the verification constraints from C_HEAP-alloced GrowableArrays to RO-alloced
- // Arrays
- SystemDictionaryShared::finalize_verification_constraints();
}
void MetaspaceShared::prepare_for_dumping() {
@@ -1509,17 +1574,11 @@
link_and_cleanup_shared_classes(CATCH);
tty->print_cr("Rewriting and linking classes: done");
+ SystemDictionary::clear_invoke_method_table();
+
VM_PopulateDumpSharedSpace op;
VMThread::execute(&op);
}
-
- if (PrintSystemDictionaryAtExit) {
- SystemDictionary::print();
- }
-
- // Since various initialization steps have been undone by this process,
- // it is not reasonable to continue running a java process.
- exit(0);
}
@@ -1529,8 +1588,14 @@
while (parser.parse_one_line()) {
Klass* klass = ClassLoaderExt::load_one_class(&parser, THREAD);
-
- CLEAR_PENDING_EXCEPTION;
+ if (HAS_PENDING_EXCEPTION) {
+ if (klass == NULL &&
+ (PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_ClassNotFoundException())) {
+ // print a warning only when the pending exception is class not found
+ tty->print_cr("Preload Warning: Cannot find %s", parser.current_class_name());
+ }
+ CLEAR_PENDING_EXCEPTION;
+ }
if (klass != NULL) {
if (log_is_enabled(Trace, cds)) {
ResourceMark rm;
--- a/hotspot/src/share/vm/memory/universe.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/memory/universe.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -63,7 +63,6 @@
#include "runtime/atomic.hpp"
#include "runtime/commandLineFlagConstraintList.hpp"
#include "runtime/deoptimization.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/java.hpp"
--- a/hotspot/src/share/vm/oops/arrayKlass.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/arrayKlass.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -187,12 +187,29 @@
void ArrayKlass::remove_unshareable_info() {
Klass::remove_unshareable_info();
+ if (_higher_dimension != NULL) {
+ ArrayKlass *ak = ArrayKlass::cast(higher_dimension());
+ ak->remove_unshareable_info();
+ }
+}
+
+void ArrayKlass::remove_java_mirror() {
+ Klass::remove_java_mirror();
+ if (_higher_dimension != NULL) {
+ ArrayKlass *ak = ArrayKlass::cast(higher_dimension());
+ ak->remove_java_mirror();
+ }
}
void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
assert(loader_data == ClassLoaderData::the_null_class_loader_data(), "array classes belong to null loader");
Klass::restore_unshareable_info(loader_data, protection_domain, CHECK);
// Klass recreates the component mirror also
+
+ if (_higher_dimension != NULL) {
+ ArrayKlass *ak = ArrayKlass::cast(higher_dimension());
+ ak->restore_unshareable_info(loader_data, protection_domain, CHECK);
+ }
}
// Printing
--- a/hotspot/src/share/vm/oops/arrayKlass.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/arrayKlass.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -130,6 +130,7 @@
// CDS support - remove and restore oops from metadata. Oops are not shared.
virtual void remove_unshareable_info();
+ virtual void remove_java_mirror();
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
// Printing
--- a/hotspot/src/share/vm/oops/constantPool.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/constantPool.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -89,8 +89,6 @@
void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) {
if (cache() != NULL) {
- MetadataFactory::free_array<u2>(loader_data, reference_map());
- set_reference_map(NULL);
MetadataFactory::free_metadata(loader_data, cache());
set_cache(NULL);
}
@@ -259,10 +257,14 @@
}
objArrayOop rr = resolved_references();
+ Array<u2>* ref_map = reference_map();
if (rr != NULL) {
- for (int i = 0; i < rr->length(); i++) {
+ int ref_map_len = ref_map == NULL ? 0 : ref_map->length();
+ int rr_len = rr->length();
+ for (int i = 0; i < rr_len; i++) {
oop p = rr->obj_at(i);
- if (p != NULL) {
+ rr->obj_at_put(i, NULL);
+ if (p != NULL && i < ref_map_len) {
int index = object_to_cp_index(i);
// Skip the entry if the string hash code is 0 since the string
// is not included in the shared string_table, see StringTable::copy_shared_string.
@@ -273,11 +275,10 @@
// have a 'bad' reference in the archived resolved_reference
// array.
rr->obj_at_put(i, op);
- } else {
- rr->obj_at_put(i, NULL);
}
}
}
+
oop archived = MetaspaceShared::archive_heap_object(rr, THREAD);
_cache->set_archived_references(archived);
set_resolved_references(NULL);
@@ -348,6 +349,26 @@
// class redefinition. Since shared ConstantPools cannot be deallocated anyway,
// we always set _on_stack to true to avoid having to change _flags during runtime.
_flags |= (_on_stack | _is_shared);
+ int num_klasses = 0;
+ for (int index = 1; index < length(); index++) { // Index 0 is unused
+ assert(!tag_at(index).is_unresolved_klass_in_error(), "This must not happen during dump time");
+ if (tag_at(index).is_klass()) {
+ // This class was resolved as a side effect of executing Java code
+ // during dump time. We need to restore it back to an UnresolvedClass,
+ // so that the proper class loading and initialization can happen
+ // at runtime.
+ CPKlassSlot kslot = klass_slot_at(index);
+ int resolved_klass_index = kslot.resolved_klass_index();
+ int name_index = kslot.name_index();
+ assert(tag_at(name_index).is_symbol(), "sanity");
+ resolved_klasses()->at_put(resolved_klass_index, NULL);
+ tag_at_put(index, JVM_CONSTANT_UnresolvedClass);
+ assert(klass_name_at(index) == symbol_at(name_index), "sanity");
+ }
+ }
+ if (cache() != NULL) {
+ cache()->remove_unshareable_info();
+ }
}
int ConstantPool::cp_to_object_index(int cp_index) {
--- a/hotspot/src/share/vm/oops/cpCache.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/cpCache.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -23,9 +23,12 @@
*/
#include "precompiled.hpp"
+#include "interpreter/bytecodeStream.hpp"
+#include "interpreter/bytecodes.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/rewriter.hpp"
#include "logging/log.hpp"
+#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp"
@@ -48,6 +51,24 @@
assert(constant_pool_index() == index, "");
}
+void ConstantPoolCacheEntry::verify_just_initialized(bool f2_used) {
+ assert((_indices & (~cp_index_mask)) == 0, "sanity");
+ assert(_f1 == NULL, "sanity");
+ assert(_flags == 0, "sanity");
+ if (!f2_used) {
+ assert(_f2 == 0, "sanity");
+ }
+}
+
+void ConstantPoolCacheEntry::reinitialize(bool f2_used) {
+ _indices &= cp_index_mask;
+ _f1 = NULL;
+ _flags = 0;
+ if (!f2_used) {
+ _f2 = 0;
+ }
+}
+
int ConstantPoolCacheEntry::make_flags(TosState state,
int option_bits,
int field_index_or_method_params) {
@@ -608,6 +629,74 @@
}
}
+void ConstantPoolCache::verify_just_initialized() {
+ DEBUG_ONLY(walk_entries_for_initialization(/*check_only = */ true));
+}
+
+void ConstantPoolCache::remove_unshareable_info() {
+ walk_entries_for_initialization(/*check_only = */ false);
+}
+
+void ConstantPoolCache::walk_entries_for_initialization(bool check_only) {
+ assert(DumpSharedSpaces, "sanity");
+ // When dumping the archive, we want to clean up the ConstantPoolCache
+ // to remove any effect of linking due to the execution of Java code --
+ // each ConstantPoolCacheEntry will have the same contents as if
+ // ConstantPoolCache::initialize has just returned:
+ //
+ // - We keep the ConstantPoolCache::constant_pool_index() bits for all entries.
+ // - We keep the "f2" field for entries used by invokedynamic and invokehandle
+ // - All other bits in the entries are cleared to zero.
+ ResourceMark rm;
+
+ InstanceKlass* ik = constant_pool()->pool_holder();
+ bool* f2_used = NEW_RESOURCE_ARRAY(bool, length());
+ memset(f2_used, 0, sizeof(bool) * length());
+
+ // Find all the slots that we need to preserve f2
+ for (int i = 0; i < ik->methods()->length(); i++) {
+ Method* m = ik->methods()->at(i);
+ RawBytecodeStream bcs(m);
+ while (!bcs.is_last_bytecode()) {
+ Bytecodes::Code opcode = bcs.raw_next();
+ switch (opcode) {
+ case Bytecodes::_invokedynamic: {
+ int index = Bytes::get_native_u4(bcs.bcp() + 1);
+ int cp_cache_index = constant_pool()->invokedynamic_cp_cache_index(index);
+ f2_used[cp_cache_index] = 1;
+ }
+ break;
+ case Bytecodes::_invokehandle: {
+ int cp_cache_index = Bytes::get_native_u2(bcs.bcp() + 1);
+ f2_used[cp_cache_index] = 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (check_only) {
+ DEBUG_ONLY(
+ for (int i=0; i<length(); i++) {
+ entry_at(i)->verify_just_initialized(f2_used[i]);
+ })
+ } else {
+ for (int i=0; i<length(); i++) {
+ entry_at(i)->reinitialize(f2_used[i]);
+ }
+ }
+}
+
+void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) {
+ assert(!is_shared(), "shared caches are not deallocated");
+ data->remove_handle(_resolved_references);
+ set_resolved_references(NULL);
+ MetadataFactory::free_array<u2>(data, _reference_map);
+ set_reference_map(NULL);
+}
+
#if INCLUDE_CDS_JAVA_HEAP
oop ConstantPoolCache::archived_references() {
assert(UseSharedSpaces, "UseSharedSpaces expected.");
--- a/hotspot/src/share/vm/oops/cpCache.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/cpCache.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -393,6 +393,9 @@
// When shifting flags as a 32-bit int, make sure we don't need an extra mask for tos_state:
assert((((u4)-1 >> tos_state_shift) & ~tos_state_mask) == 0, "no need for tos_state mask");
}
+
+ void verify_just_initialized(bool f2_used);
+ void reinitialize(bool f2_used);
};
@@ -464,7 +467,11 @@
// Assembly code support
static int resolved_references_offset_in_bytes() { return offset_of(ConstantPoolCache, _resolved_references); }
+ // CDS support
+ void remove_unshareable_info();
+ void verify_just_initialized();
private:
+ void walk_entries_for_initialization(bool check_only);
void set_length(int length) { _length = length; }
static int header_size() { return sizeof(ConstantPoolCache) / wordSize; }
@@ -510,9 +517,9 @@
void dump_cache();
#endif // INCLUDE_JVMTI
- // Deallocate - no fields to deallocate
+ // RedefineClasses support
DEBUG_ONLY(bool on_stack() { return false; })
- void deallocate_contents(ClassLoaderData* data) {}
+ void deallocate_contents(ClassLoaderData* data);
bool is_klass() const { return false; }
// Printing
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -747,10 +747,10 @@
char* message = NEW_RESOURCE_ARRAY(char, msglen);
if (NULL == message) {
// Out of memory: can't create detailed error message
- THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);
+ THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);
} else {
jio_snprintf(message, msglen, "%s%s", desc, className);
- THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);
+ THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);
}
}
@@ -2067,14 +2067,14 @@
m->remove_unshareable_info();
}
+ // do array classes also.
+ if (array_klasses() != NULL) {
+ array_klasses()->remove_unshareable_info();
+ }
+
// These are not allocated from metaspace, but they should should all be empty
- // during dump time, so we don't need to worry about them in InstanceKlass::metaspace_pointers_do().
+ // during dump time, so we don't need to worry about them in InstanceKlass::iterate().
guarantee(_source_debug_extension == NULL, "must be");
- guarantee(_oop_map_cache == NULL, "must be");
- guarantee(_init_thread == NULL, "must be");
- guarantee(_oop_map_cache == NULL, "must be");
- guarantee(_jni_ids == NULL, "must be");
- guarantee(_methods_jmethod_ids == NULL, "must be");
guarantee(_dep_context == DependencyContext::EMPTY, "must be");
guarantee(_osr_nmethods_head == NULL, "must be");
@@ -2082,12 +2082,20 @@
guarantee(_breakpoints == NULL, "must be");
guarantee(_previous_versions == NULL, "must be");
#endif
+
+ _init_thread = NULL;
+ _methods_jmethod_ids = NULL;
+ _jni_ids = NULL;
+ _oop_map_cache = NULL;
}
-static void restore_unshareable_in_class(Klass* k, TRAPS) {
- // Array classes have null protection domain.
- // --> see ArrayKlass::complete_create_array_klass()
- k->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK);
+void InstanceKlass::remove_java_mirror() {
+ Klass::remove_java_mirror();
+
+ // do array classes also.
+ if (array_klasses() != NULL) {
+ array_klasses()->remove_java_mirror();
+ }
}
void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
@@ -2114,7 +2122,11 @@
// restore constant pool resolved references
constants()->restore_unshareable_info(CHECK);
- array_klasses_do(restore_unshareable_in_class, CHECK);
+ if (array_klasses() != NULL) {
+ // Array classes have null protection domain.
+ // --> see ArrayKlass::complete_create_array_klass()
+ array_klasses()->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK);
+ }
}
// returns true IFF is_in_error_state() has been changed as a result of this call.
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -327,8 +327,6 @@
}
void set_class_loader_type(s2 loader_type) {
- assert(( _misc_flags & loader_type_bits()) == 0,
- "Should only be called once for each class.");
switch (loader_type) {
case ClassLoader::BOOT_LOADER:
_misc_flags |= _misc_is_shared_boot_class;
@@ -1335,6 +1333,7 @@
public:
// CDS support - remove and restore oops from metadata. Oops are not shared.
virtual void remove_unshareable_info();
+ virtual void remove_java_mirror();
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
// jvm support
--- a/hotspot/src/share/vm/oops/klass.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/klass.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -512,11 +512,13 @@
void Klass::remove_unshareable_info() {
assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
TRACE_REMOVE_ID(this);
+ if (log_is_enabled(Trace, cds, unshareable)) {
+ ResourceMark rm;
+ log_trace(cds, unshareable)("remove: %s", external_name());
+ }
set_subklass(NULL);
set_next_sibling(NULL);
- // Clear the java mirror
- set_java_mirror(NULL);
set_next_link(NULL);
// Null out class_loader_data because we don't share that yet.
@@ -524,10 +526,23 @@
set_is_shared();
}
+void Klass::remove_java_mirror() {
+ assert (DumpSharedSpaces, "only called for DumpSharedSpaces");
+ if (log_is_enabled(Trace, cds, unshareable)) {
+ ResourceMark rm;
+ log_trace(cds, unshareable)("remove java_mirror: %s", external_name());
+ }
+ set_java_mirror(NULL);
+}
+
void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
assert(is_klass(), "ensure C++ vtable is restored");
assert(is_shared(), "must be set");
TRACE_RESTORE_ID(this);
+ if (log_is_enabled(Trace, cds, unshareable)) {
+ ResourceMark rm;
+ log_trace(cds, unshareable)("restore: %s", external_name());
+ }
// If an exception happened during CDS restore, some of these fields may already be
// set. We leave the class on the CLD list, even if incomplete so that we don't
--- a/hotspot/src/share/vm/oops/klass.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/klass.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -479,6 +479,7 @@
// CDS support - remove and restore oops from metadata. Oops are not shared.
virtual void remove_unshareable_info();
+ virtual void remove_java_mirror();
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
protected:
--- a/hotspot/src/share/vm/oops/method.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/method.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -944,10 +944,6 @@
_from_compiled_entry = cds_adapter->get_c2i_entry_trampoline();
assert(*((int*)_from_compiled_entry) == 0, "must be NULL during dump time, to be initialized at run time");
-
- // In case of DumpSharedSpaces, _method_data should always be NULL.
- assert(_method_data == NULL, "unexpected method data?");
-
set_method_data(NULL);
clear_method_counters();
}
--- a/hotspot/src/share/vm/oops/oopHandle.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/oops/oopHandle.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -46,6 +46,9 @@
OopHandle(oop* w) : _obj(w) {}
oop resolve() const { return (_obj == NULL) ? (oop)NULL : *_obj; }
+
+ // Used only for removing handle.
+ oop* ptr_raw() { return _obj; }
};
#endif // SHARE_VM_OOPS_OOPHANDLE_HPP
--- a/hotspot/src/share/vm/opto/runtime.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/opto/runtime.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -61,7 +61,6 @@
#include "opto/runtime.hpp"
#include "opto/subnode.hpp"
#include "runtime/atomic.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/javaCalls.hpp"
--- a/hotspot/src/share/vm/prims/jni.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/prims/jni.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -62,7 +62,6 @@
#include "runtime/atomic.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/fieldDescriptor.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/java.hpp"
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -2497,14 +2497,13 @@
library = os::dll_load(agent, ebuf, sizeof ebuf);
} else {
// Try to load the agent from the standard dll directory
- if (os::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
+ if (os::dll_locate_lib(buffer, sizeof(buffer), Arguments::get_dll_dir(),
agent)) {
library = os::dll_load(buffer, ebuf, sizeof ebuf);
}
if (library == NULL) {
- // not found - try local path
- char ns[1] = {0};
- if (os::dll_build_name(buffer, sizeof(buffer), ns, agent)) {
+ // not found - try OS default library path
+ if (os::dll_build_name(buffer, sizeof(buffer), agent)) {
library = os::dll_load(buffer, ebuf, sizeof ebuf);
}
}
--- a/hotspot/src/share/vm/runtime/arguments.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -78,7 +78,6 @@
char* Arguments::_java_command = NULL;
SystemProperty* Arguments::_system_properties = NULL;
const char* Arguments::_gc_log_filename = NULL;
-bool Arguments::_has_profile = false;
size_t Arguments::_conservative_max_heap_alignment = 0;
size_t Arguments::_min_heap_size = 0;
Arguments::Mode Arguments::_mode = _mixed;
@@ -379,6 +378,9 @@
{ "MaxGCMinorPauseMillis", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() },
{ "UseConcMarkSweepGC", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() },
{ "MonitorInUseLists", JDK_Version::jdk(10),JDK_Version::undefined(), JDK_Version::undefined() },
+ { "MaxRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() },
+ { "MinRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() },
+ { "InitialRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() },
// --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in:
{ "DefaultMaxRAMFraction", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() },
@@ -1291,13 +1293,11 @@
"jdk.module.limitmods",
"jdk.module.path",
"jdk.module.upgrade.path",
- "jdk.module.addmods.0",
"jdk.module.patch.0" };
const char* unsupported_options[] = { "-m", // cannot use at dump time
"--limit-modules", // ignored at dump time
"--module-path", // ignored at dump time
"--upgrade-module-path", // ignored at dump time
- "--add-modules", // ignored at dump time
"--patch-module" // ignored at dump time
};
assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
@@ -2069,20 +2069,33 @@
}
}
+ // Convert deprecated flags
+ if (FLAG_IS_DEFAULT(MaxRAMPercentage) &&
+ !FLAG_IS_DEFAULT(MaxRAMFraction))
+ MaxRAMPercentage = 100.0 / MaxRAMFraction;
+
+ if (FLAG_IS_DEFAULT(MinRAMPercentage) &&
+ !FLAG_IS_DEFAULT(MinRAMFraction))
+ MinRAMPercentage = 100.0 / MinRAMFraction;
+
+ if (FLAG_IS_DEFAULT(InitialRAMPercentage) &&
+ !FLAG_IS_DEFAULT(InitialRAMFraction))
+ InitialRAMPercentage = 100.0 / InitialRAMFraction;
+
// If the maximum heap size has not been set with -Xmx,
// then set it as fraction of the size of physical memory,
// respecting the maximum and minimum sizes of the heap.
if (FLAG_IS_DEFAULT(MaxHeapSize)) {
- julong reasonable_max = phys_mem / MaxRAMFraction;
-
- if (phys_mem <= MaxHeapSize * MinRAMFraction) {
+ julong reasonable_max = (julong)((phys_mem * MaxRAMPercentage) / 100);
+ if (phys_mem <= (julong)((MaxHeapSize * MinRAMPercentage) / 100)) {
// Small physical memory, so use a minimum fraction of it for the heap
- reasonable_max = phys_mem / MinRAMFraction;
+ reasonable_max = (julong)((phys_mem * MinRAMPercentage) / 100);
} else {
// Not-small physical memory, so require a heap at least
// as large as MaxHeapSize
reasonable_max = MAX2(reasonable_max, (julong)MaxHeapSize);
}
+
if (!FLAG_IS_DEFAULT(ErgoHeapSizeLimit) && ErgoHeapSizeLimit != 0) {
// Limit the heap size to ErgoHeapSizeLimit
reasonable_max = MIN2(reasonable_max, (julong)ErgoHeapSizeLimit);
@@ -2135,7 +2148,7 @@
reasonable_minimum = limit_by_allocatable_memory(reasonable_minimum);
if (InitialHeapSize == 0) {
- julong reasonable_initial = phys_mem / InitialRAMFraction;
+ julong reasonable_initial = (julong)((phys_mem * InitialRAMPercentage) / 100);
reasonable_initial = MAX3(reasonable_initial, reasonable_minimum, (julong)min_heap_size());
reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize);
@@ -2667,17 +2680,11 @@
}
// Do final processing now that all arguments have been parsed
- result = finalize_vm_init_args();
+ result = finalize_vm_init_args(patch_mod_javabase);
if (result != JNI_OK) {
return result;
}
-#if INCLUDE_CDS
- if (UseSharedSpaces && patch_mod_javabase) {
- no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched.");
- }
-#endif
-
return JNI_OK;
}
@@ -3152,16 +3159,12 @@
if (FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true) != Flag::SUCCESS) {
return JNI_EINVAL;
}
- // -Xprof
+ // -Xprof
} else if (match_option(option, "-Xprof")) {
-#if INCLUDE_FPROF
- log_warning(arguments)("Option -Xprof was deprecated in version 9 and will likely be removed in a future release.");
- _has_profile = true;
-#else // INCLUDE_FPROF
- jio_fprintf(defaultStream::error_stream(),
- "Flat profiling is not supported in this VM.\n");
- return JNI_ERR;
-#endif // INCLUDE_FPROF
+ char version[256];
+ // Obsolete in JDK 10
+ JDK_Version::jdk(10).to_string(version, sizeof(version));
+ warning("Ignoring option %s; support was removed in %s", option->optionString, version);
// -Xconcurrentio
} else if (match_option(option, "-Xconcurrentio")) {
if (FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true) != Flag::SUCCESS) {
@@ -3602,7 +3605,7 @@
return nonEmptyDirs;
}
-jint Arguments::finalize_vm_init_args() {
+jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) {
// check if the default lib/endorsed directory exists; if so, error
char path[JVM_MAXPATHLEN];
const char* fileSep = os::file_separator();
@@ -3723,6 +3726,17 @@
}
#endif
+#if INCLUDE_CDS
+ if (DumpSharedSpaces) {
+ // Disable biased locking now as it interferes with the clean up of
+ // the archived Klasses and Java string objects (at dump time only).
+ UseBiasedLocking = false;
+ }
+ if (UseSharedSpaces && patch_mod_javabase) {
+ no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched.");
+ }
+#endif
+
return JNI_OK;
}
--- a/hotspot/src/share/vm/runtime/arguments.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/arguments.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -412,7 +412,6 @@
static bool _sun_java_launcher_is_altjvm;
// Option flags
- static bool _has_profile;
static const char* _gc_log_filename;
// Value of the conservative maximum heap alignment needed
static size_t _conservative_max_heap_alignment;
@@ -536,7 +535,7 @@
const JavaVMInitArgs *java_options_args,
const JavaVMInitArgs *cmd_line_args);
static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, Flag::Flags origin);
- static jint finalize_vm_init_args();
+ static jint finalize_vm_init_args(bool patch_mod_javabase);
static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type);
static bool is_bad_option(const JavaVMOption* option, jboolean ignore) {
@@ -696,9 +695,6 @@
// -Dsun.java.launcher.pid
static int sun_java_launcher_pid() { return _sun_java_launcher_pid; }
- // -Xprof
- static bool has_profile() { return _has_profile; }
-
// -Xms
static size_t min_heap_size() { return _min_heap_size; }
static void set_min_heap_size(size_t v) { _min_heap_size = v; }
--- a/hotspot/src/share/vm/runtime/arguments_ext.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/arguments_ext.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, 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
@@ -36,6 +36,7 @@
// Otherwise returns false.
static inline bool process_options(const JavaVMOption *option) { return false; }
static inline void report_unsupported_options() { }
+ static inline bool using_AppCDS() { return false; }
};
void ArgumentsExt::set_gc_specific_flags() {
--- a/hotspot/src/share/vm/runtime/fprofiler.cpp Fri Sep 01 14:13:09 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1623 +0,0 @@
-/*
- * Copyright (c) 1997, 2016, 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 "code/codeCache.hpp"
-#include "code/vtableStubs.hpp"
-#include "gc/shared/collectedHeap.inline.hpp"
-#include "interpreter/interpreter.hpp"
-#include "memory/allocation.inline.hpp"
-#include "memory/resourceArea.hpp"
-#include "memory/universe.inline.hpp"
-#include "oops/oop.inline.hpp"
-#include "oops/symbol.hpp"
-#include "runtime/deoptimization.hpp"
-#include "runtime/fprofiler.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/stubCodeGenerator.hpp"
-#include "runtime/stubRoutines.hpp"
-#include "runtime/task.hpp"
-#include "runtime/thread.inline.hpp"
-#include "runtime/vframe.hpp"
-#include "utilities/macros.hpp"
-
-// Static fields of FlatProfiler
-int FlatProfiler::received_gc_ticks = 0;
-int FlatProfiler::vm_operation_ticks = 0;
-int FlatProfiler::threads_lock_ticks = 0;
-int FlatProfiler::class_loader_ticks = 0;
-int FlatProfiler::extra_ticks = 0;
-int FlatProfiler::blocked_ticks = 0;
-int FlatProfiler::deopt_ticks = 0;
-int FlatProfiler::unknown_ticks = 0;
-int FlatProfiler::interpreter_ticks = 0;
-int FlatProfiler::compiler_ticks = 0;
-int FlatProfiler::received_ticks = 0;
-int FlatProfiler::delivered_ticks = 0;
-int* FlatProfiler::bytecode_ticks = NULL;
-int* FlatProfiler::bytecode_ticks_stub = NULL;
-int FlatProfiler::all_int_ticks = 0;
-int FlatProfiler::all_comp_ticks = 0;
-int FlatProfiler::all_ticks = 0;
-bool FlatProfiler::full_profile_flag = false;
-ThreadProfiler* FlatProfiler::thread_profiler = NULL;
-ThreadProfiler* FlatProfiler::vm_thread_profiler = NULL;
-FlatProfilerTask* FlatProfiler::task = NULL;
-elapsedTimer FlatProfiler::timer;
-int FlatProfiler::interval_ticks_previous = 0;
-IntervalData* FlatProfiler::interval_data = NULL;
-
-ThreadProfiler::ThreadProfiler() {
- // Space for the ProfilerNodes
- const int area_size = 1 * ProfilerNodeSize * 1024;
- area_bottom = AllocateHeap(area_size, mtInternal);
- area_top = area_bottom;
- area_limit = area_bottom + area_size;
-
- // ProfilerNode pointer table
- table = NEW_C_HEAP_ARRAY(ProfilerNode*, table_size, mtInternal);
- initialize();
- engaged = false;
-}
-
-ThreadProfiler::~ThreadProfiler() {
- FreeHeap(area_bottom);
- area_bottom = NULL;
- area_top = NULL;
- area_limit = NULL;
- FreeHeap(table);
- table = NULL;
-}
-
-// Statics for ThreadProfiler
-int ThreadProfiler::table_size = 1024;
-
-int ThreadProfiler::entry(int value) {
- value = (value > 0) ? value : -value;
- return value % table_size;
-}
-
-ThreadProfilerMark::ThreadProfilerMark(ThreadProfilerMark::Region r) {
- _r = r;
- _pp = NULL;
- assert(((r > ThreadProfilerMark::noRegion) && (r < ThreadProfilerMark::maxRegion)), "ThreadProfilerMark::Region out of bounds");
- Thread* tp = Thread::current();
- if (tp != NULL && tp->is_Java_thread()) {
- JavaThread* jtp = (JavaThread*) tp;
- ThreadProfiler* pp = jtp->get_thread_profiler();
- _pp = pp;
- if (pp != NULL) {
- pp->region_flag[r] = true;
- }
- }
-}
-
-ThreadProfilerMark::~ThreadProfilerMark() {
- if (_pp != NULL) {
- _pp->region_flag[_r] = false;
- }
- _pp = NULL;
-}
-
-// Random other statics
-static const int col1 = 2; // position of output column 1
-static const int col2 = 11; // position of output column 2
-static const int col3 = 25; // position of output column 3
-static const int col4 = 55; // position of output column 4
-
-
-// Used for detailed profiling of nmethods.
-class PCRecorder : AllStatic {
- private:
- static int* counters;
- static address base;
- enum {
- bucket_size = 16
- };
- static int index_for(address pc) { return (pc - base)/bucket_size; }
- static address pc_for(int index) { return base + (index * bucket_size); }
- static int size() {
- return ((int)CodeCache::max_capacity())/bucket_size * BytesPerWord;
- }
- public:
- static address bucket_start_for(address pc) {
- if (counters == NULL) return NULL;
- return pc_for(index_for(pc));
- }
- static int bucket_count_for(address pc) { return counters[index_for(pc)]; }
- static void init();
- static void record(address pc);
- static void print();
- static void print_blobs(CodeBlob* cb);
-};
-
-int* PCRecorder::counters = NULL;
-address PCRecorder::base = NULL;
-
-void PCRecorder::init() {
- MutexLockerEx lm(CodeCache_lock, Mutex::_no_safepoint_check_flag);
- int s = size();
- counters = NEW_C_HEAP_ARRAY(int, s, mtInternal);
- for (int index = 0; index < s; index++) {
- counters[index] = 0;
- }
- base = CodeCache::low_bound();
-}
-
-void PCRecorder::record(address pc) {
- if (counters == NULL) return;
- assert(CodeCache::contains(pc), "must be in CodeCache");
- counters[index_for(pc)]++;
-}
-
-
-address FlatProfiler::bucket_start_for(address pc) {
- return PCRecorder::bucket_start_for(pc);
-}
-
-int FlatProfiler::bucket_count_for(address pc) {
- return PCRecorder::bucket_count_for(pc);
-}
-
-void PCRecorder::print() {
- if (counters == NULL) return;
-
- tty->cr();
- tty->print_cr("Printing compiled methods with PC buckets having more than " INTX_FORMAT " ticks", ProfilerPCTickThreshold);
- tty->print_cr("===================================================================");
- tty->cr();
-
- GrowableArray<CodeBlob*>* candidates = new GrowableArray<CodeBlob*>(20);
-
-
- int s;
- {
- MutexLockerEx lm(CodeCache_lock, Mutex::_no_safepoint_check_flag);
- s = size();
- }
-
- for (int index = 0; index < s; index++) {
- int count = counters[index];
- if (count > ProfilerPCTickThreshold) {
- address pc = pc_for(index);
- CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
- if (cb != NULL && candidates->find(cb) < 0) {
- candidates->push(cb);
- }
- }
- }
- for (int i = 0; i < candidates->length(); i++) {
- print_blobs(candidates->at(i));
- }
-}
-
-void PCRecorder::print_blobs(CodeBlob* cb) {
- if (cb != NULL) {
- cb->print();
- if (cb->is_nmethod()) {
- ((nmethod*)cb)->print_code();
- }
- tty->cr();
- } else {
- tty->print_cr("stub code");
- }
-}
-
-class tick_counter { // holds tick info for one node
- public:
- int ticks_in_code;
- int ticks_in_native;
-
- tick_counter() { ticks_in_code = ticks_in_native = 0; }
- tick_counter(int code, int native) { ticks_in_code = code; ticks_in_native = native; }
-
- int total() const {
- return (ticks_in_code + ticks_in_native);
- }
-
- void add(tick_counter* a) {
- ticks_in_code += a->ticks_in_code;
- ticks_in_native += a->ticks_in_native;
- }
-
- void update(TickPosition where) {
- switch(where) {
- case tp_code: ticks_in_code++; break;
- case tp_native: ticks_in_native++; break;
- }
- }
-
- void print_code(outputStream* st, int total_ticks) {
- st->print("%5.1f%% %5d ", total() * 100.0 / total_ticks, ticks_in_code);
- }
-
- void print_native(outputStream* st) {
- st->print(" + %5d ", ticks_in_native);
- }
-};
-
-class ProfilerNode {
- private:
- ProfilerNode* _next;
- public:
- tick_counter ticks;
-
- public:
-
- void* operator new(size_t size, ThreadProfiler* tp) throw();
- void operator delete(void* p);
-
- ProfilerNode() {
- _next = NULL;
- }
-
- virtual ~ProfilerNode() {
- if (_next)
- delete _next;
- }
-
- void set_next(ProfilerNode* n) { _next = n; }
- ProfilerNode* next() { return _next; }
-
- void update(TickPosition where) { ticks.update(where);}
- int total_ticks() { return ticks.total(); }
-
- virtual bool is_interpreted() const { return false; }
- virtual bool is_compiled() const { return false; }
- virtual bool is_stub() const { return false; }
- virtual bool is_runtime_stub() const{ return false; }
- virtual void oops_do(OopClosure* f) = 0;
-
- virtual bool interpreted_match(Method* m) const { return false; }
- virtual bool compiled_match(Method* m ) const { return false; }
- virtual bool stub_match(Method* m, const char* name) const { return false; }
- virtual bool adapter_match() const { return false; }
- virtual bool runtimeStub_match(const CodeBlob* stub, const char* name) const { return false; }
- virtual bool unknown_compiled_match(const CodeBlob* cb) const { return false; }
-
- static void print_title(outputStream* st) {
- st->print(" + native");
- st->fill_to(col3);
- st->print("Method");
- st->fill_to(col4);
- st->cr();
- }
-
- static void print_total(outputStream* st, tick_counter* t, int total, const char* msg) {
- t->print_code(st, total);
- st->fill_to(col2);
- t->print_native(st);
- st->fill_to(col3);
- st->print("%s", msg);
- st->cr();
- }
-
- virtual Method* method() = 0;
-
- virtual void print_method_on(outputStream* st) {
- int limit;
- int i;
- Method* m = method();
- Symbol* k = m->klass_name();
- // Print the class name with dots instead of slashes
- limit = k->utf8_length();
- for (i = 0 ; i < limit ; i += 1) {
- char c = (char) k->byte_at(i);
- if (c == '/') {
- c = '.';
- }
- st->print("%c", c);
- }
- if (limit > 0) {
- st->print(".");
- }
- Symbol* n = m->name();
- limit = n->utf8_length();
- for (i = 0 ; i < limit ; i += 1) {
- char c = (char) n->byte_at(i);
- st->print("%c", c);
- }
- if (Verbose || WizardMode) {
- // Disambiguate overloaded methods
- Symbol* sig = m->signature();
- sig->print_symbol_on(st);
- } else if (MethodHandles::is_signature_polymorphic(m->intrinsic_id()))
- // compare with Method::print_short_name
- MethodHandles::print_as_basic_type_signature_on(st, m->signature(), true);
- }
-
- virtual void print(outputStream* st, int total_ticks) {
- ticks.print_code(st, total_ticks);
- st->fill_to(col2);
- ticks.print_native(st);
- st->fill_to(col3);
- print_method_on(st);
- st->cr();
- }
-
- // for hashing into the table
- static int hash(Method* method) {
- // The point here is to try to make something fairly unique
- // out of the fields we can read without grabbing any locks
- // since the method may be locked when we need the hash.
- return (
- method->code_size() ^
- method->max_stack() ^
- method->max_locals() ^
- method->size_of_parameters());
- }
-
- // for sorting
- static int compare(ProfilerNode** a, ProfilerNode** b) {
- return (*b)->total_ticks() - (*a)->total_ticks();
- }
-};
-
-void* ProfilerNode::operator new(size_t size, ThreadProfiler* tp) throw() {
- void* result = (void*) tp->area_top;
- tp->area_top += size;
-
- if (tp->area_top > tp->area_limit) {
- fatal("flat profiler buffer overflow");
- }
- return result;
-}
-
-void ProfilerNode::operator delete(void* p){
-}
-
-class interpretedNode : public ProfilerNode {
- private:
- Method* _method;
- oop _class_loader; // needed to keep metadata for the method alive
- public:
- interpretedNode(Method* method, TickPosition where) : ProfilerNode() {
- _method = method;
- _class_loader = method->method_holder()->class_loader();
- update(where);
- }
-
- bool is_interpreted() const { return true; }
-
- bool interpreted_match(Method* m) const {
- return _method == m;
- }
-
- void oops_do(OopClosure* f) {
- f->do_oop(&_class_loader);
- }
-
- Method* method() { return _method; }
-
- static void print_title(outputStream* st) {
- st->fill_to(col1);
- st->print("%11s", "Interpreted");
- ProfilerNode::print_title(st);
- }
-
- void print(outputStream* st, int total_ticks) {
- ProfilerNode::print(st, total_ticks);
- }
-
- void print_method_on(outputStream* st) {
- ProfilerNode::print_method_on(st);
- MethodCounters* mcs = method()->method_counters();
- if (Verbose && mcs != NULL) mcs->invocation_counter()->print_short();
- }
-};
-
-class compiledNode : public ProfilerNode {
- private:
- Method* _method;
- oop _class_loader; // needed to keep metadata for the method alive
- public:
- compiledNode(Method* method, TickPosition where) : ProfilerNode() {
- _method = method;
- _class_loader = method->method_holder()->class_loader();
- update(where);
- }
- bool is_compiled() const { return true; }
-
- bool compiled_match(Method* m) const {
- return _method == m;
- }
-
- Method* method() { return _method; }
-
- void oops_do(OopClosure* f) {
- f->do_oop(&_class_loader);
- }
-
- static void print_title(outputStream* st) {
- st->fill_to(col1);
- st->print("%11s", "Compiled");
- ProfilerNode::print_title(st);
- }
-
- void print(outputStream* st, int total_ticks) {
- ProfilerNode::print(st, total_ticks);
- }
-
- void print_method_on(outputStream* st) {
- ProfilerNode::print_method_on(st);
- }
-};
-
-class stubNode : public ProfilerNode {
- private:
- Method* _method;
- oop _class_loader; // needed to keep metadata for the method alive
- const char* _symbol; // The name of the nearest VM symbol (for +ProfileVM). Points to a unique string
- public:
- stubNode(Method* method, const char* name, TickPosition where) : ProfilerNode() {
- _method = method;
- _class_loader = method->method_holder()->class_loader();
- _symbol = name;
- update(where);
- }
-
- bool is_stub() const { return true; }
-
- void oops_do(OopClosure* f) {
- f->do_oop(&_class_loader);
- }
-
- bool stub_match(Method* m, const char* name) const {
- return (_method == m) && (_symbol == name);
- }
-
- Method* method() { return _method; }
-
- static void print_title(outputStream* st) {
- st->fill_to(col1);
- st->print("%11s", "Stub");
- ProfilerNode::print_title(st);
- }
-
- void print(outputStream* st, int total_ticks) {
- ProfilerNode::print(st, total_ticks);
- }
-
- void print_method_on(outputStream* st) {
- ProfilerNode::print_method_on(st);
- print_symbol_on(st);
- }
-
- void print_symbol_on(outputStream* st) {
- if(_symbol) {
- st->print(" (%s)", _symbol);
- }
- }
-};
-
-class adapterNode : public ProfilerNode {
- public:
- adapterNode(TickPosition where) : ProfilerNode() {
- update(where);
- }
- bool is_compiled() const { return true; }
-
- bool adapter_match() const { return true; }
-
- Method* method() { return NULL; }
-
- void oops_do(OopClosure* f) {
- ;
- }
-
- void print(outputStream* st, int total_ticks) {
- ProfilerNode::print(st, total_ticks);
- }
-
- void print_method_on(outputStream* st) {
- st->print("%s", "adapters");
- }
-};
-
-class runtimeStubNode : public ProfilerNode {
- private:
- const RuntimeStub* _stub;
- const char* _symbol; // The name of the nearest VM symbol when ProfileVM is on. Points to a unique string.
- public:
- runtimeStubNode(const CodeBlob* stub, const char* name, TickPosition where) : ProfilerNode(), _stub(NULL), _symbol(name) {
- assert(stub->is_runtime_stub(), "wrong code blob");
- _stub = (RuntimeStub*) stub;
- update(where);
- }
-
- bool is_runtime_stub() const { return true; }
-
- bool runtimeStub_match(const CodeBlob* stub, const char* name) const {
- assert(stub->is_runtime_stub(), "wrong code blob");
- return _stub->entry_point() == ((RuntimeStub*)stub)->entry_point() &&
- (_symbol == name);
- }
-
- Method* method() { return NULL; }
-
- static void print_title(outputStream* st) {
- st->fill_to(col1);
- st->print("%11s", "Runtime stub");
- ProfilerNode::print_title(st);
- }
-
- void oops_do(OopClosure* f) {
- ;
- }
-
- void print(outputStream* st, int total_ticks) {
- ProfilerNode::print(st, total_ticks);
- }
-
- void print_method_on(outputStream* st) {
- st->print("%s", _stub->name());
- print_symbol_on(st);
- }
-
- void print_symbol_on(outputStream* st) {
- if(_symbol) {
- st->print(" (%s)", _symbol);
- }
- }
-};
-
-
-class unknown_compiledNode : public ProfilerNode {
- const char *_name;
- public:
- unknown_compiledNode(const CodeBlob* cb, TickPosition where) : ProfilerNode() {
- if ( cb->is_buffer_blob() )
- _name = ((const BufferBlob*)cb)->name();
- else
- _name = ((const SingletonBlob*)cb)->name();
- update(where);
- }
- bool is_compiled() const { return true; }
-
- bool unknown_compiled_match(const CodeBlob* cb) const {
- if ( cb->is_buffer_blob() )
- return !strcmp(((const BufferBlob*)cb)->name(), _name);
- else
- return !strcmp(((const SingletonBlob*)cb)->name(), _name);
- }
-
- Method* method() { return NULL; }
-
- void oops_do(OopClosure* f) {
- ;
- }
-
- void print(outputStream* st, int total_ticks) {
- ProfilerNode::print(st, total_ticks);
- }
-
- void print_method_on(outputStream* st) {
- st->print("%s", _name);
- }
-};
-
-class vmNode : public ProfilerNode {
- private:
- const char* _name; // "optional" name obtained by os means such as dll lookup
- public:
- vmNode(const TickPosition where) : ProfilerNode() {
- _name = NULL;
- update(where);
- }
-
- vmNode(const char* name, const TickPosition where) : ProfilerNode() {
- _name = os::strdup(name);
- update(where);
- }
-
- ~vmNode() {
- if (_name != NULL) {
- os::free((void*)_name);
- }
- }
-
- const char *name() const { return _name; }
- bool is_compiled() const { return true; }
-
- bool vm_match(const char* name) const { return strcmp(name, _name) == 0; }
-
- Method* method() { return NULL; }
-
- static int hash(const char* name){
- // Compute a simple hash
- const char* cp = name;
- int h = 0;
-
- if(name != NULL){
- while(*cp != '\0'){
- h = (h << 1) ^ *cp;
- cp++;
- }
- }
- return h;
- }
-
- void oops_do(OopClosure* f) {
- ;
- }
-
- void print(outputStream* st, int total_ticks) {
- ProfilerNode::print(st, total_ticks);
- }
-
- void print_method_on(outputStream* st) {
- if(_name==NULL){
- st->print("%s", "unknown code");
- }
- else {
- st->print("%s", _name);
- }
- }
-};
-
-void ThreadProfiler::interpreted_update(Method* method, TickPosition where) {
- int index = entry(ProfilerNode::hash(method));
- if (!table[index]) {
- table[index] = new (this) interpretedNode(method, where);
- } else {
- ProfilerNode* prev = table[index];
- for(ProfilerNode* node = prev; node; node = node->next()) {
- if (node->interpreted_match(method)) {
- node->update(where);
- return;
- }
- prev = node;
- }
- prev->set_next(new (this) interpretedNode(method, where));
- }
-}
-
-void ThreadProfiler::compiled_update(Method* method, TickPosition where) {
- int index = entry(ProfilerNode::hash(method));
- if (!table[index]) {
- table[index] = new (this) compiledNode(method, where);
- } else {
- ProfilerNode* prev = table[index];
- for(ProfilerNode* node = prev; node; node = node->next()) {
- if (node->compiled_match(method)) {
- node->update(where);
- return;
- }
- prev = node;
- }
- prev->set_next(new (this) compiledNode(method, where));
- }
-}
-
-void ThreadProfiler::stub_update(Method* method, const char* name, TickPosition where) {
- int index = entry(ProfilerNode::hash(method));
- if (!table[index]) {
- table[index] = new (this) stubNode(method, name, where);
- } else {
- ProfilerNode* prev = table[index];
- for(ProfilerNode* node = prev; node; node = node->next()) {
- if (node->stub_match(method, name)) {
- node->update(where);
- return;
- }
- prev = node;
- }
- prev->set_next(new (this) stubNode(method, name, where));
- }
-}
-
-void ThreadProfiler::adapter_update(TickPosition where) {
- int index = 0;
- if (!table[index]) {
- table[index] = new (this) adapterNode(where);
- } else {
- ProfilerNode* prev = table[index];
- for(ProfilerNode* node = prev; node; node = node->next()) {
- if (node->adapter_match()) {
- node->update(where);
- return;
- }
- prev = node;
- }
- prev->set_next(new (this) adapterNode(where));
- }
-}
-
-void ThreadProfiler::runtime_stub_update(const CodeBlob* stub, const char* name, TickPosition where) {
- int index = 0;
- if (!table[index]) {
- table[index] = new (this) runtimeStubNode(stub, name, where);
- } else {
- ProfilerNode* prev = table[index];
- for(ProfilerNode* node = prev; node; node = node->next()) {
- if (node->runtimeStub_match(stub, name)) {
- node->update(where);
- return;
- }
- prev = node;
- }
- prev->set_next(new (this) runtimeStubNode(stub, name, where));
- }
-}
-
-
-void ThreadProfiler::unknown_compiled_update(const CodeBlob* cb, TickPosition where) {
- int index = 0;
- if (!table[index]) {
- table[index] = new (this) unknown_compiledNode(cb, where);
- } else {
- ProfilerNode* prev = table[index];
- for(ProfilerNode* node = prev; node; node = node->next()) {
- if (node->unknown_compiled_match(cb)) {
- node->update(where);
- return;
- }
- prev = node;
- }
- prev->set_next(new (this) unknown_compiledNode(cb, where));
- }
-}
-
-void ThreadProfiler::vm_update(TickPosition where) {
- vm_update(NULL, where);
-}
-
-void ThreadProfiler::vm_update(const char* name, TickPosition where) {
- int index = entry(vmNode::hash(name));
- assert(index >= 0, "Must be positive");
- // Note that we call strdup below since the symbol may be resource allocated
- if (!table[index]) {
- table[index] = new (this) vmNode(name, where);
- } else {
- ProfilerNode* prev = table[index];
- for(ProfilerNode* node = prev; node; node = node->next()) {
- if (((vmNode *)node)->vm_match(name)) {
- node->update(where);
- return;
- }
- prev = node;
- }
- prev->set_next(new (this) vmNode(name, where));
- }
-}
-
-
-class FlatProfilerTask : public PeriodicTask {
-public:
- FlatProfilerTask(int interval_time) : PeriodicTask(interval_time) {}
- void task();
-};
-
-void FlatProfiler::record_vm_operation() {
- if (Universe::heap()->is_gc_active()) {
- FlatProfiler::received_gc_ticks += 1;
- return;
- }
-
- if (DeoptimizationMarker::is_active()) {
- FlatProfiler::deopt_ticks += 1;
- return;
- }
-
- FlatProfiler::vm_operation_ticks += 1;
-}
-
-void FlatProfiler::record_vm_tick() {
- // Profile the VM Thread itself if needed
- // This is done without getting the Threads_lock and we can go deep
- // inside Safepoint, etc.
- if( ProfileVM ) {
- ResourceMark rm;
- ExtendedPC epc;
- const char *name = NULL;
- char buf[256];
- buf[0] = '\0';
-
- vm_thread_profiler->inc_thread_ticks();
-
- // Get a snapshot of a current VMThread pc (and leave it running!)
- // The call may fail in some circumstances
- epc = os::get_thread_pc(VMThread::vm_thread());
- if(epc.pc() != NULL) {
- if (os::dll_address_to_function_name(epc.pc(), buf, sizeof(buf), NULL)) {
- name = buf;
- }
- }
- if (name != NULL) {
- vm_thread_profiler->vm_update(name, tp_native);
- }
- }
-}
-
-void FlatProfiler::record_thread_ticks() {
-
- int maxthreads, suspendedthreadcount;
- JavaThread** threadsList;
- bool interval_expired = false;
-
- if (ProfileIntervals &&
- (FlatProfiler::received_ticks >= interval_ticks_previous + ProfileIntervalsTicks)) {
- interval_expired = true;
- interval_ticks_previous = FlatProfiler::received_ticks;
- }
-
- // Try not to wait for the Threads_lock
- if (Threads_lock->try_lock()) {
- { // Threads_lock scope
- maxthreads = Threads::number_of_threads();
- threadsList = NEW_C_HEAP_ARRAY(JavaThread *, maxthreads, mtInternal);
- suspendedthreadcount = 0;
- for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) {
- if (tp->is_Compiler_thread()) {
- // Only record ticks for active compiler threads
- CompilerThread* cthread = (CompilerThread*)tp;
- if (cthread->task() != NULL) {
- // The compiler is active. If we need to access any of the fields
- // of the compiler task we should suspend the CompilerThread first.
- FlatProfiler::compiler_ticks += 1;
- continue;
- }
- }
-
- // First externally suspend all threads by marking each for
- // external suspension - so it will stop at its next transition
- // Then do a safepoint
- ThreadProfiler* pp = tp->get_thread_profiler();
- if (pp != NULL && pp->engaged) {
- MutexLockerEx ml(tp->SR_lock(), Mutex::_no_safepoint_check_flag);
- if (!tp->is_external_suspend() && !tp->is_exiting()) {
- tp->set_external_suspend();
- threadsList[suspendedthreadcount++] = tp;
- }
- }
- }
- Threads_lock->unlock();
- }
- // Suspend each thread. This call should just return
- // for any threads that have already self-suspended
- // Net result should be one safepoint
- for (int j = 0; j < suspendedthreadcount; j++) {
- JavaThread *tp = threadsList[j];
- if (tp) {
- tp->java_suspend();
- }
- }
-
- // We are responsible for resuming any thread on this list
- for (int i = 0; i < suspendedthreadcount; i++) {
- JavaThread *tp = threadsList[i];
- if (tp) {
- ThreadProfiler* pp = tp->get_thread_profiler();
- if (pp != NULL && pp->engaged) {
- HandleMark hm;
- FlatProfiler::delivered_ticks += 1;
- if (interval_expired) {
- FlatProfiler::interval_record_thread(pp);
- }
- // This is the place where we check to see if a user thread is
- // blocked waiting for compilation.
- if (tp->blocked_on_compilation()) {
- pp->compiler_ticks += 1;
- pp->interval_data_ref()->inc_compiling();
- } else {
- pp->record_tick(tp);
- }
- }
- MutexLocker ml(Threads_lock);
- tp->java_resume();
- }
- }
- if (interval_expired) {
- FlatProfiler::interval_print();
- FlatProfiler::interval_reset();
- }
-
- FREE_C_HEAP_ARRAY(JavaThread *, threadsList);
- } else {
- // Couldn't get the threads lock, just record that rather than blocking
- FlatProfiler::threads_lock_ticks += 1;
- }
-
-}
-
-void FlatProfilerTask::task() {
- FlatProfiler::received_ticks += 1;
-
- if (ProfileVM) {
- FlatProfiler::record_vm_tick();
- }
-
- VM_Operation* op = VMThread::vm_operation();
- if (op != NULL) {
- FlatProfiler::record_vm_operation();
- if (SafepointSynchronize::is_at_safepoint()) {
- return;
- }
- }
- FlatProfiler::record_thread_ticks();
-}
-
-void ThreadProfiler::record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks) {
- FlatProfiler::all_int_ticks++;
- if (!FlatProfiler::full_profile()) {
- return;
- }
-
- if (!fr.is_interpreted_frame_valid(thread)) {
- // tick came at a bad time
- interpreter_ticks += 1;
- FlatProfiler::interpreter_ticks += 1;
- return;
- }
-
- // The frame has been fully validated so we can trust the method and bci
-
- Method* method = *fr.interpreter_frame_method_addr();
-
- interpreted_update(method, where);
-
- // update byte code table
- InterpreterCodelet* desc = Interpreter::codelet_containing(fr.pc());
- if (desc != NULL && desc->bytecode() >= 0) {
- ticks[desc->bytecode()]++;
- }
-}
-
-void ThreadProfiler::record_compiled_tick(JavaThread* thread, frame fr, TickPosition where) {
- const char *name = NULL;
- TickPosition localwhere = where;
-
- FlatProfiler::all_comp_ticks++;
- if (!FlatProfiler::full_profile()) return;
-
- CodeBlob* cb = fr.cb();
-
- // For runtime stubs, record as native rather than as compiled
- if (cb->is_runtime_stub()) {
- RegisterMap map(thread, false);
- fr = fr.sender(&map);
- cb = fr.cb();
- localwhere = tp_native;
- }
-
- Method* method = cb->is_compiled() ? cb->as_compiled_method()->method() : (Method*) NULL;
- if (method == NULL) {
- if (cb->is_runtime_stub())
- runtime_stub_update(cb, name, localwhere);
- else
- unknown_compiled_update(cb, localwhere);
- }
- else {
- if (method->is_native()) {
- stub_update(method, name, localwhere);
- } else {
- compiled_update(method, localwhere);
- }
- }
-}
-
-extern "C" void find(int x);
-
-
-void ThreadProfiler::record_tick_for_running_frame(JavaThread* thread, frame fr) {
- // The tick happened in real code -> non VM code
- if (fr.is_interpreted_frame()) {
- interval_data_ref()->inc_interpreted();
- record_interpreted_tick(thread, fr, tp_code, FlatProfiler::bytecode_ticks);
- return;
- }
-
- if (CodeCache::contains(fr.pc())) {
- interval_data_ref()->inc_compiled();
- PCRecorder::record(fr.pc());
- record_compiled_tick(thread, fr, tp_code);
- return;
- }
-
- if (VtableStubs::stub_containing(fr.pc()) != NULL) {
- unknown_ticks_array[ut_vtable_stubs] += 1;
- return;
- }
-
- frame caller = fr.profile_find_Java_sender_frame(thread);
-
- if (caller.sp() != NULL && caller.pc() != NULL) {
- record_tick_for_calling_frame(thread, caller);
- return;
- }
-
- unknown_ticks_array[ut_running_frame] += 1;
- FlatProfiler::unknown_ticks += 1;
-}
-
-void ThreadProfiler::record_tick_for_calling_frame(JavaThread* thread, frame fr) {
- // The tick happened in VM code
- interval_data_ref()->inc_native();
- if (fr.is_interpreted_frame()) {
- record_interpreted_tick(thread, fr, tp_native, FlatProfiler::bytecode_ticks_stub);
- return;
- }
- if (CodeCache::contains(fr.pc())) {
- record_compiled_tick(thread, fr, tp_native);
- return;
- }
-
- frame caller = fr.profile_find_Java_sender_frame(thread);
-
- if (caller.sp() != NULL && caller.pc() != NULL) {
- record_tick_for_calling_frame(thread, caller);
- return;
- }
-
- unknown_ticks_array[ut_calling_frame] += 1;
- FlatProfiler::unknown_ticks += 1;
-}
-
-void ThreadProfiler::record_tick(JavaThread* thread) {
- FlatProfiler::all_ticks++;
- thread_ticks += 1;
-
- // Here's another way to track global state changes.
- // When the class loader starts it marks the ThreadProfiler to tell it it is in the class loader
- // and we check that here.
- // This is more direct, and more than one thread can be in the class loader at a time,
- // but it does mean the class loader has to know about the profiler.
- if (region_flag[ThreadProfilerMark::classLoaderRegion]) {
- class_loader_ticks += 1;
- FlatProfiler::class_loader_ticks += 1;
- return;
- } else if (region_flag[ThreadProfilerMark::extraRegion]) {
- extra_ticks += 1;
- FlatProfiler::extra_ticks += 1;
- return;
- }
- // Note that the WatcherThread can now stop for safepoints
- uint32_t debug_bits = 0;
- if (!thread->wait_for_ext_suspend_completion(SuspendRetryCount,
- SuspendRetryDelay, &debug_bits)) {
- unknown_ticks_array[ut_unknown_thread_state] += 1;
- FlatProfiler::unknown_ticks += 1;
- return;
- }
-
- frame fr;
-
- switch (thread->thread_state()) {
- case _thread_in_native:
- case _thread_in_native_trans:
- case _thread_in_vm:
- case _thread_in_vm_trans:
- if (thread->profile_last_Java_frame(&fr)) {
- if (fr.is_runtime_frame()) {
- RegisterMap map(thread, false);
- fr = fr.sender(&map);
- }
- record_tick_for_calling_frame(thread, fr);
- } else {
- unknown_ticks_array[ut_no_last_Java_frame] += 1;
- FlatProfiler::unknown_ticks += 1;
- }
- break;
- // handle_special_runtime_exit_condition self-suspends threads in Java
- case _thread_in_Java:
- case _thread_in_Java_trans:
- if (thread->profile_last_Java_frame(&fr)) {
- if (fr.is_safepoint_blob_frame()) {
- RegisterMap map(thread, false);
- fr = fr.sender(&map);
- }
- record_tick_for_running_frame(thread, fr);
- } else {
- unknown_ticks_array[ut_no_last_Java_frame] += 1;
- FlatProfiler::unknown_ticks += 1;
- }
- break;
- case _thread_blocked:
- case _thread_blocked_trans:
- if (thread->osthread() && thread->osthread()->get_state() == RUNNABLE) {
- if (thread->profile_last_Java_frame(&fr)) {
- if (fr.is_safepoint_blob_frame()) {
- RegisterMap map(thread, false);
- fr = fr.sender(&map);
- record_tick_for_running_frame(thread, fr);
- } else {
- record_tick_for_calling_frame(thread, fr);
- }
- } else {
- unknown_ticks_array[ut_no_last_Java_frame] += 1;
- FlatProfiler::unknown_ticks += 1;
- }
- } else {
- blocked_ticks += 1;
- FlatProfiler::blocked_ticks += 1;
- }
- break;
- case _thread_uninitialized:
- case _thread_new:
- // not used, included for completeness
- case _thread_new_trans:
- unknown_ticks_array[ut_no_last_Java_frame] += 1;
- FlatProfiler::unknown_ticks += 1;
- break;
- default:
- unknown_ticks_array[ut_unknown_thread_state] += 1;
- FlatProfiler::unknown_ticks += 1;
- break;
- }
- return;
-}
-
-void ThreadProfiler::engage() {
- engaged = true;
- timer.start();
-}
-
-void ThreadProfiler::disengage() {
- engaged = false;
- timer.stop();
-}
-
-void ThreadProfiler::initialize() {
- for (int index = 0; index < table_size; index++) {
- table[index] = NULL;
- }
- thread_ticks = 0;
- blocked_ticks = 0;
- compiler_ticks = 0;
- interpreter_ticks = 0;
- for (int ut = 0; ut < ut_end; ut += 1) {
- unknown_ticks_array[ut] = 0;
- }
- region_flag[ThreadProfilerMark::classLoaderRegion] = false;
- class_loader_ticks = 0;
- region_flag[ThreadProfilerMark::extraRegion] = false;
- extra_ticks = 0;
- timer.start();
- interval_data_ref()->reset();
-}
-
-void ThreadProfiler::reset() {
- timer.stop();
- if (table != NULL) {
- for (int index = 0; index < table_size; index++) {
- ProfilerNode* n = table[index];
- if (n != NULL) {
- delete n;
- }
- }
- }
- initialize();
-}
-
-void FlatProfiler::allocate_table() {
- { // Bytecode table
- bytecode_ticks = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes, mtInternal);
- bytecode_ticks_stub = NEW_C_HEAP_ARRAY(int, Bytecodes::number_of_codes, mtInternal);
- for(int index = 0; index < Bytecodes::number_of_codes; index++) {
- bytecode_ticks[index] = 0;
- bytecode_ticks_stub[index] = 0;
- }
- }
-
- if (ProfilerRecordPC) PCRecorder::init();
-
- interval_data = NEW_C_HEAP_ARRAY(IntervalData, interval_print_size, mtInternal);
- FlatProfiler::interval_reset();
-}
-
-void FlatProfiler::engage(JavaThread* mainThread, bool fullProfile) {
- full_profile_flag = fullProfile;
- if (bytecode_ticks == NULL) {
- allocate_table();
- }
- if(ProfileVM && (vm_thread_profiler == NULL)){
- vm_thread_profiler = new ThreadProfiler();
- }
- if (task == NULL) {
- task = new FlatProfilerTask(WatcherThread::delay_interval);
- task->enroll();
- }
- timer.start();
- if (mainThread != NULL) {
- // When mainThread was created, it might not have a ThreadProfiler
- ThreadProfiler* pp = mainThread->get_thread_profiler();
- if (pp == NULL) {
- mainThread->set_thread_profiler(new ThreadProfiler());
- } else {
- pp->reset();
- }
- mainThread->get_thread_profiler()->engage();
- }
- // This is where we would assign thread_profiler
- // if we wanted only one thread_profiler for all threads.
- thread_profiler = NULL;
-}
-
-void FlatProfiler::disengage() {
- if (!task) {
- return;
- }
- timer.stop();
- task->disenroll();
- delete task;
- task = NULL;
- if (thread_profiler != NULL) {
- thread_profiler->disengage();
- } else {
- MutexLocker tl(Threads_lock);
- for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) {
- ThreadProfiler* pp = tp->get_thread_profiler();
- if (pp != NULL) {
- pp->disengage();
- }
- }
- }
-}
-
-void FlatProfiler::reset() {
- if (task) {
- disengage();
- }
-
- class_loader_ticks = 0;
- extra_ticks = 0;
- received_gc_ticks = 0;
- vm_operation_ticks = 0;
- compiler_ticks = 0;
- deopt_ticks = 0;
- interpreter_ticks = 0;
- blocked_ticks = 0;
- unknown_ticks = 0;
- received_ticks = 0;
- delivered_ticks = 0;
- timer.stop();
-}
-
-bool FlatProfiler::is_active() {
- return task != NULL;
-}
-
-void FlatProfiler::print_byte_code_statistics() {
- GrowableArray <ProfilerNode*>* array = new GrowableArray<ProfilerNode*>(200);
-
- tty->print_cr(" Bytecode ticks:");
- for (int index = 0; index < Bytecodes::number_of_codes; index++) {
- if (FlatProfiler::bytecode_ticks[index] > 0 || FlatProfiler::bytecode_ticks_stub[index] > 0) {
- tty->print_cr(" %4d %4d = %s",
- FlatProfiler::bytecode_ticks[index],
- FlatProfiler::bytecode_ticks_stub[index],
- Bytecodes::name( (Bytecodes::Code) index));
- }
- }
- tty->cr();
-}
-
-void print_ticks(const char* title, int ticks, int total) {
- if (ticks > 0) {
- tty->print("%5.1f%% %5d", ticks * 100.0 / total, ticks);
- tty->fill_to(col3);
- tty->print("%s", title);
- tty->cr();
- }
-}
-
-void ThreadProfiler::print(const char* thread_name) {
- ResourceMark rm;
- MutexLocker ppl(ProfilePrint_lock);
- int index = 0; // Declared outside for loops for portability
-
- if (table == NULL) {
- return;
- }
-
- if (thread_ticks <= 0) {
- return;
- }
-
- const char* title = "too soon to tell";
- double secs = timer.seconds();
-
- GrowableArray <ProfilerNode*>* array = new GrowableArray<ProfilerNode*>(200);
- for(index = 0; index < table_size; index++) {
- for(ProfilerNode* node = table[index]; node; node = node->next())
- array->append(node);
- }
-
- array->sort(&ProfilerNode::compare);
-
- // compute total (sanity check)
- int active =
- class_loader_ticks +
- compiler_ticks +
- interpreter_ticks +
- unknown_ticks();
- for (index = 0; index < array->length(); index++) {
- active += array->at(index)->ticks.total();
- }
- int total = active + blocked_ticks;
-
- tty->cr();
- tty->print_cr("Flat profile of %3.2f secs (%d total ticks): %s", secs, total, thread_name);
- if (total != thread_ticks) {
- print_ticks("Lost ticks", thread_ticks-total, thread_ticks);
- }
- tty->cr();
-
- // print interpreted methods
- tick_counter interpreted_ticks;
- bool has_interpreted_ticks = false;
- int print_count = 0;
- for (index = 0; index < array->length(); index++) {
- ProfilerNode* n = array->at(index);
- if (n->is_interpreted()) {
- interpreted_ticks.add(&n->ticks);
- if (!has_interpreted_ticks) {
- interpretedNode::print_title(tty);
- has_interpreted_ticks = true;
- }
- if (print_count++ < ProfilerNumberOfInterpretedMethods) {
- n->print(tty, active);
- }
- }
- }
- if (has_interpreted_ticks) {
- if (print_count <= ProfilerNumberOfInterpretedMethods) {
- title = "Total interpreted";
- } else {
- title = "Total interpreted (including elided)";
- }
- interpretedNode::print_total(tty, &interpreted_ticks, active, title);
- tty->cr();
- }
-
- // print compiled methods
- tick_counter compiled_ticks;
- bool has_compiled_ticks = false;
- print_count = 0;
- for (index = 0; index < array->length(); index++) {
- ProfilerNode* n = array->at(index);
- if (n->is_compiled()) {
- compiled_ticks.add(&n->ticks);
- if (!has_compiled_ticks) {
- compiledNode::print_title(tty);
- has_compiled_ticks = true;
- }
- if (print_count++ < ProfilerNumberOfCompiledMethods) {
- n->print(tty, active);
- }
- }
- }
- if (has_compiled_ticks) {
- if (print_count <= ProfilerNumberOfCompiledMethods) {
- title = "Total compiled";
- } else {
- title = "Total compiled (including elided)";
- }
- compiledNode::print_total(tty, &compiled_ticks, active, title);
- tty->cr();
- }
-
- // print stub methods
- tick_counter stub_ticks;
- bool has_stub_ticks = false;
- print_count = 0;
- for (index = 0; index < array->length(); index++) {
- ProfilerNode* n = array->at(index);
- if (n->is_stub()) {
- stub_ticks.add(&n->ticks);
- if (!has_stub_ticks) {
- stubNode::print_title(tty);
- has_stub_ticks = true;
- }
- if (print_count++ < ProfilerNumberOfStubMethods) {
- n->print(tty, active);
- }
- }
- }
- if (has_stub_ticks) {
- if (print_count <= ProfilerNumberOfStubMethods) {
- title = "Total stub";
- } else {
- title = "Total stub (including elided)";
- }
- stubNode::print_total(tty, &stub_ticks, active, title);
- tty->cr();
- }
-
- // print runtime stubs
- tick_counter runtime_stub_ticks;
- bool has_runtime_stub_ticks = false;
- print_count = 0;
- for (index = 0; index < array->length(); index++) {
- ProfilerNode* n = array->at(index);
- if (n->is_runtime_stub()) {
- runtime_stub_ticks.add(&n->ticks);
- if (!has_runtime_stub_ticks) {
- runtimeStubNode::print_title(tty);
- has_runtime_stub_ticks = true;
- }
- if (print_count++ < ProfilerNumberOfRuntimeStubNodes) {
- n->print(tty, active);
- }
- }
- }
- if (has_runtime_stub_ticks) {
- if (print_count <= ProfilerNumberOfRuntimeStubNodes) {
- title = "Total runtime stubs";
- } else {
- title = "Total runtime stubs (including elided)";
- }
- runtimeStubNode::print_total(tty, &runtime_stub_ticks, active, title);
- tty->cr();
- }
-
- if (blocked_ticks + class_loader_ticks + interpreter_ticks + compiler_ticks + unknown_ticks() != 0) {
- tty->fill_to(col1);
- tty->print_cr("Thread-local ticks:");
- print_ticks("Blocked (of total)", blocked_ticks, total);
- print_ticks("Class loader", class_loader_ticks, active);
- print_ticks("Extra", extra_ticks, active);
- print_ticks("Interpreter", interpreter_ticks, active);
- print_ticks("Compilation", compiler_ticks, active);
- print_ticks("Unknown: vtable stubs", unknown_ticks_array[ut_vtable_stubs], active);
- print_ticks("Unknown: null method", unknown_ticks_array[ut_null_method], active);
- print_ticks("Unknown: running frame", unknown_ticks_array[ut_running_frame], active);
- print_ticks("Unknown: calling frame", unknown_ticks_array[ut_calling_frame], active);
- print_ticks("Unknown: no pc", unknown_ticks_array[ut_no_pc], active);
- print_ticks("Unknown: no last frame", unknown_ticks_array[ut_no_last_Java_frame], active);
- print_ticks("Unknown: thread_state", unknown_ticks_array[ut_unknown_thread_state], active);
- tty->cr();
- }
-
- if (WizardMode) {
- tty->print_cr("Node area used: " INTX_FORMAT " Kb", (area_top - area_bottom) / 1024);
- }
- reset();
-}
-
-/*
-ThreadProfiler::print_unknown(){
- if (table == NULL) {
- return;
- }
-
- if (thread_ticks <= 0) {
- return;
- }
-} */
-
-void FlatProfiler::print(int unused) {
- ResourceMark rm;
- if (thread_profiler != NULL) {
- thread_profiler->print("All threads");
- } else {
- MutexLocker tl(Threads_lock);
- for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) {
- ThreadProfiler* pp = tp->get_thread_profiler();
- if (pp != NULL) {
- pp->print(tp->get_thread_name());
- }
- }
- }
-
- if (ProfilerPrintByteCodeStatistics) {
- print_byte_code_statistics();
- }
-
- if (non_method_ticks() > 0) {
- tty->cr();
- tty->print_cr("Global summary of %3.2f seconds:", timer.seconds());
- print_ticks("Received ticks", received_ticks, received_ticks);
- print_ticks("Received GC ticks", received_gc_ticks, received_ticks);
- print_ticks("Compilation", compiler_ticks, received_ticks);
- print_ticks("Deoptimization", deopt_ticks, received_ticks);
- print_ticks("Other VM operations", vm_operation_ticks, received_ticks);
-#ifndef PRODUCT
- print_ticks("Blocked ticks", blocked_ticks, received_ticks);
- print_ticks("Threads_lock blocks", threads_lock_ticks, received_ticks);
- print_ticks("Delivered ticks", delivered_ticks, received_ticks);
- print_ticks("All ticks", all_ticks, received_ticks);
-#endif
- print_ticks("Class loader", class_loader_ticks, received_ticks);
- print_ticks("Extra ", extra_ticks, received_ticks);
- print_ticks("Interpreter", interpreter_ticks, received_ticks);
- print_ticks("Unknown code", unknown_ticks, received_ticks);
- }
-
- PCRecorder::print();
-
- if(ProfileVM){
- tty->cr();
- vm_thread_profiler->print("VM Thread");
- }
-}
-
-void IntervalData::print_header(outputStream* st) {
- st->print("i/c/n/g");
-}
-
-void IntervalData::print_data(outputStream* st) {
- st->print("%d/%d/%d/%d", interpreted(), compiled(), native(), compiling());
-}
-
-void FlatProfiler::interval_record_thread(ThreadProfiler* tp) {
- IntervalData id = tp->interval_data();
- int total = id.total();
- tp->interval_data_ref()->reset();
-
- // Insertion sort the data, if it's relevant.
- for (int i = 0; i < interval_print_size; i += 1) {
- if (total > interval_data[i].total()) {
- for (int j = interval_print_size - 1; j > i; j -= 1) {
- interval_data[j] = interval_data[j-1];
- }
- interval_data[i] = id;
- break;
- }
- }
-}
-
-void FlatProfiler::interval_print() {
- if ((interval_data[0].total() > 0)) {
- tty->stamp();
- tty->print("\t");
- IntervalData::print_header(tty);
- for (int i = 0; i < interval_print_size; i += 1) {
- if (interval_data[i].total() > 0) {
- tty->print("\t");
- interval_data[i].print_data(tty);
- }
- }
- tty->cr();
- }
-}
-
-void FlatProfiler::interval_reset() {
- for (int i = 0; i < interval_print_size; i += 1) {
- interval_data[i].reset();
- }
-}
-
-void ThreadProfiler::oops_do(OopClosure* f) {
- if (table == NULL) return;
-
- for(int index = 0; index < table_size; index++) {
- for(ProfilerNode* node = table[index]; node; node = node->next())
- node->oops_do(f);
- }
-}
-
-void FlatProfiler::oops_do(OopClosure* f) {
- if (thread_profiler != NULL) {
- thread_profiler->oops_do(f);
- } else {
- for (JavaThread* tp = Threads::first(); tp != NULL; tp = tp->next()) {
- ThreadProfiler* pp = tp->get_thread_profiler();
- if (pp != NULL) {
- pp->oops_do(f);
- }
- }
- }
-}
--- a/hotspot/src/share/vm/runtime/fprofiler.hpp Fri Sep 01 14:13:09 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,319 +0,0 @@
-/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_VM_RUNTIME_FPROFILER_HPP
-#define SHARE_VM_RUNTIME_FPROFILER_HPP
-
-#include "utilities/macros.hpp"
-#include "runtime/timer.hpp"
-
-// a simple flat profiler for Java
-
-
-// Forward declaration of classes defined in this header file
-class ThreadProfiler;
-class ThreadProfilerMark;
-class FlatProfiler;
-class IntervalData;
-
-// Declarations of classes defined only in the implementation.
-class ProfilerNode;
-class FlatProfilerTask;
-
-enum TickPosition {
- tp_code,
- tp_native
-};
-
-// One of these guys is constructed as we enter interesting regions
-// and destructed as we exit the region. While we are in the region
-// ticks are allotted to the region.
-class ThreadProfilerMark: public StackObj {
-public:
- // For now, the only thread-specific region is the class loader.
- enum Region { noRegion, classLoaderRegion, extraRegion, maxRegion };
-
- ThreadProfilerMark(Region) NOT_FPROF_RETURN;
- ~ThreadProfilerMark() NOT_FPROF_RETURN;
-
-private:
- ThreadProfiler* _pp;
- Region _r;
-};
-
-#if INCLUDE_FPROF
-
-class IntervalData VALUE_OBJ_CLASS_SPEC {
- // Just to keep these things all together
-private:
- int _interpreted;
- int _compiled;
- int _native;
- int _compiling;
-public:
- int interpreted() {
- return _interpreted;
- }
- int compiled() {
- return _compiled;
- }
- int native() {
- return _native;
- }
- int compiling() {
- return _compiling;
- }
- int total() {
- return (interpreted() + compiled() + native() + compiling());
- }
- void inc_interpreted() {
- _interpreted += 1;
- }
- void inc_compiled() {
- _compiled += 1;
- }
- void inc_native() {
- _native += 1;
- }
- void inc_compiling() {
- _compiling += 1;
- }
- void reset() {
- _interpreted = 0;
- _compiled = 0;
- _native = 0;
- _compiling = 0;
- }
- static void print_header(outputStream* st);
- void print_data(outputStream* st);
-};
-#endif // INCLUDE_FPROF
-
-class ThreadProfiler: public CHeapObj<mtInternal> {
-public:
- ThreadProfiler() NOT_FPROF_RETURN;
- ~ThreadProfiler() NOT_FPROF_RETURN;
-
- // Resets the profiler
- void reset() NOT_FPROF_RETURN;
-
- // Activates the profiler for a certain thread
- void engage() NOT_FPROF_RETURN;
-
- // Deactivates the profiler
- void disengage() NOT_FPROF_RETURN;
-
- // Prints the collected profiling information
- void print(const char* thread_name) NOT_FPROF_RETURN;
-
- // Garbage Collection Support
- void oops_do(OopClosure* f) NOT_FPROF_RETURN;
-
-#if INCLUDE_FPROF
-private:
- // for recording ticks.
- friend class ProfilerNode;
- char* area_bottom; // preallocated area for pnodes
- char* area_top;
- char* area_limit;
- static int table_size;
- ProfilerNode** table;
-
-private:
- void record_interpreted_tick(JavaThread* thread, frame fr, TickPosition where, int* ticks);
- void record_compiled_tick (JavaThread* thread, frame fr, TickPosition where);
- void interpreted_update(Method* method, TickPosition where);
- void compiled_update (Method* method, TickPosition where);
- void stub_update (Method* method, const char* name, TickPosition where);
- void adapter_update (TickPosition where);
-
- void runtime_stub_update(const CodeBlob* stub, const char* name, TickPosition where);
- void unknown_compiled_update (const CodeBlob* cb, TickPosition where);
-
- void vm_update (TickPosition where);
- void vm_update (const char* name, TickPosition where);
-
- void record_tick_for_running_frame(JavaThread* thread, frame fr);
- void record_tick_for_calling_frame(JavaThread* thread, frame fr);
-
- void initialize();
-
- static int entry(int value);
-
-
-private:
- friend class FlatProfiler;
- void record_tick(JavaThread* thread);
- bool engaged;
- // so we can do percentages for this thread, and quick checks for activity
- int thread_ticks;
- int compiler_ticks;
- int interpreter_ticks;
-
-public:
- void inc_thread_ticks() { thread_ticks += 1; }
-
-private:
- friend class ThreadProfilerMark;
- // counters for thread-specific regions
- bool region_flag[ThreadProfilerMark::maxRegion];
- int class_loader_ticks;
- int extra_ticks;
-
-private:
- // other thread-specific regions
- int blocked_ticks;
- enum UnknownTickSites {
- ut_null_method,
- ut_vtable_stubs,
- ut_running_frame,
- ut_calling_frame,
- ut_no_pc,
- ut_no_last_Java_frame,
- ut_unknown_thread_state,
- ut_end
- };
- int unknown_ticks_array[ut_end];
- int unknown_ticks() {
- int result = 0;
- for (int ut = 0; ut < ut_end; ut += 1) {
- result += unknown_ticks_array[ut];
- }
- return result;
- }
-
- elapsedTimer timer;
-
- // For interval timing
-private:
- IntervalData _interval_data;
- IntervalData interval_data() {
- return _interval_data;
- }
- IntervalData* interval_data_ref() {
- return &_interval_data;
- }
-#endif // INCLUDE_FPROF
-};
-
-class FlatProfiler: AllStatic {
-public:
- static void reset() NOT_FPROF_RETURN ;
- static void engage(JavaThread* mainThread, bool fullProfile) NOT_FPROF_RETURN ;
- static void disengage() NOT_FPROF_RETURN ;
- static void print(int unused) NOT_FPROF_RETURN ;
- static bool is_active() NOT_FPROF_RETURN_(false) ;
-
- // This is NULL if each thread has its own thread profiler,
- // else this is the single thread profiler used by all threads.
- // In particular it makes a difference during garbage collection,
- // where you only want to traverse each thread profiler once.
- static ThreadProfiler* get_thread_profiler() NOT_FPROF_RETURN_(NULL);
-
- // Garbage Collection Support
- static void oops_do(OopClosure* f) NOT_FPROF_RETURN ;
-
- // Support for disassembler to inspect the PCRecorder
-
- // Returns the start address for a given pc
- // NULL is returned if the PCRecorder is inactive
- static address bucket_start_for(address pc) NOT_FPROF_RETURN_(NULL);
-
- enum { MillisecsPerTick = 10 }; // ms per profiling ticks
-
- // Returns the number of ticks recorded for the bucket
- // pc belongs to.
- static int bucket_count_for(address pc) NOT_FPROF_RETURN_(0);
-
-#if INCLUDE_FPROF
-
- private:
- static bool full_profile() {
- return full_profile_flag;
- }
-
- friend class ThreadProfiler;
- // the following group of ticks cover everything that's not attributed to individual Java methods
- static int received_gc_ticks; // ticks during which gc was active
- static int vm_operation_ticks; // total ticks in vm_operations other than GC
- static int threads_lock_ticks; // the number of times we couldn't get the Threads_lock without blocking
- static int blocked_ticks; // ticks when the thread was blocked.
- static int class_loader_ticks; // total ticks in class loader
- static int extra_ticks; // total ticks an extra temporary measuring
- static int compiler_ticks; // total ticks in compilation
- static int interpreter_ticks; // ticks in unknown interpreted method
- static int deopt_ticks; // ticks in deoptimization
- static int unknown_ticks; // ticks that cannot be categorized
- static int received_ticks; // ticks that were received by task
- static int delivered_ticks; // ticks that were delivered by task
- static int non_method_ticks() {
- return
- ( received_gc_ticks
- + vm_operation_ticks
- + deopt_ticks
- + threads_lock_ticks
- + blocked_ticks
- + compiler_ticks
- + interpreter_ticks
- + unknown_ticks );
- }
- static elapsedTimer timer;
-
- // Counts of each of the byte codes
- static int* bytecode_ticks;
- static int* bytecode_ticks_stub;
- static void print_byte_code_statistics();
-
- // the ticks below are for continuous profiling (to adjust recompilation, etc.)
- static int all_ticks; // total count of ticks received so far
- static int all_int_ticks; // ticks in interpreter
- static int all_comp_ticks; // ticks in compiled code (+ native)
- static bool full_profile_flag; // collecting full profile?
-
- // to accumulate thread-specific data
- // if we aren't profiling individual threads.
- static ThreadProfiler* thread_profiler;
- static ThreadProfiler* vm_thread_profiler;
-
- static void allocate_table();
-
- // The task that periodically interrupts things.
- friend class FlatProfilerTask;
- static FlatProfilerTask* task;
- static void record_vm_operation();
- static void record_vm_tick();
- static void record_thread_ticks();
-
- // For interval analysis
- private:
- static int interval_ticks_previous; // delivered_ticks from the last interval
- static void interval_record_thread(ThreadProfiler* tp); // extract ticks from ThreadProfiler.
- static void interval_print(); // print interval data.
- static void interval_reset(); // reset interval data.
- enum {interval_print_size = 10};
- static IntervalData* interval_data;
-#endif // INCLUDE_FPROF
-};
-
-#endif // SHARE_VM_RUNTIME_FPROFILER_HPP
--- a/hotspot/src/share/vm/runtime/globals.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/globals.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -2037,7 +2037,7 @@
\
product(size_t, ErgoHeapSizeLimit, 0, \
"Maximum ergonomically set heap size (in bytes); zero means use " \
- "MaxRAM / MaxRAMFraction") \
+ "MaxRAM * MaxRAMPercentage / 100") \
range(0, max_uintx) \
\
experimental(bool, UseCGroupMemoryLimitForHeap, false, \
@@ -2046,18 +2046,34 @@
\
product(uintx, MaxRAMFraction, 4, \
"Maximum fraction (1/n) of real memory used for maximum heap " \
- "size") \
+ "size. " \
+ "Deprecated, use MaxRAMPercentage instead") \
range(1, max_uintx) \
\
product(uintx, MinRAMFraction, 2, \
"Minimum fraction (1/n) of real memory used for maximum heap " \
- "size on systems with small physical memory size") \
+ "size on systems with small physical memory size. " \
+ "Deprecated, use MinRAMPercentage instead") \
range(1, max_uintx) \
\
product(uintx, InitialRAMFraction, 64, \
- "Fraction (1/n) of real memory used for initial heap size") \
+ "Fraction (1/n) of real memory used for initial heap size. " \
+ "Deprecated, use InitialRAMPercentage instead") \
range(1, max_uintx) \
\
+ product(double, MaxRAMPercentage, 25.0, \
+ "Maximum percentage of real memory used for maximum heap size") \
+ range(0.0, 100.0) \
+ \
+ product(double, MinRAMPercentage, 50.0, \
+ "Minimum percentage of real memory used for maximum heap" \
+ "size on systems with small physical memory size") \
+ range(0.0, 100.0) \
+ \
+ product(double, InitialRAMPercentage, 1.5625, \
+ "Percentage of real memory used for initial heap size") \
+ range(0.0, 100.0) \
+ \
develop(uintx, MaxVirtMemFraction, 2, \
"Maximum fraction (1/n) of virtual memory used for ergonomically "\
"determining maximum heap size") \
--- a/hotspot/src/share/vm/runtime/java.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/java.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -55,7 +55,6 @@
#include "runtime/biasedLocking.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/deoptimization.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/java.hpp"
@@ -465,12 +464,6 @@
WatcherThread::stop();
}
- // Print statistics gathered (profiling ...)
- if (Arguments::has_profile()) {
- FlatProfiler::disengage();
- FlatProfiler::print(10);
- }
-
// shut down the StatSampler task
StatSampler::disengage();
StatSampler::destroy();
--- a/hotspot/src/share/vm/runtime/javaCalls.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/javaCalls.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -308,9 +308,6 @@
}
void JavaCalls::call_helper(JavaValue* result, const methodHandle& method, JavaCallArguments* args, TRAPS) {
- // During dumping, Java execution environment is not fully initialized. Also, Java execution
- // may cause undesirable side-effects in the class metadata.
- assert(!DumpSharedSpaces, "must not execute Java bytecodes when dumping");
JavaThread* thread = (JavaThread*)THREAD;
assert(thread->is_Java_thread(), "must be called by a java thread");
--- a/hotspot/src/share/vm/runtime/os.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/os.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -235,6 +235,82 @@
return OS_OK;
}
+bool os::dll_build_name(char* buffer, size_t size, const char* fname) {
+ int n = jio_snprintf(buffer, size, "%s%s%s", JNI_LIB_PREFIX, fname, JNI_LIB_SUFFIX);
+ return (n != -1);
+}
+
+// Helper for dll_locate_lib.
+// Pass buffer and printbuffer as we already printed the path to buffer
+// when we called get_current_directory. This way we avoid another buffer
+// of size MAX_PATH.
+static bool conc_path_file_and_check(char *buffer, char *printbuffer, size_t printbuflen,
+ const char* pname, char lastchar, const char* fname) {
+
+ // Concatenate path and file name, but don't print double path separators.
+ const char *filesep = (WINDOWS_ONLY(lastchar == ':' ||) lastchar == os::file_separator()[0]) ?
+ "" : os::file_separator();
+ int ret = jio_snprintf(printbuffer, printbuflen, "%s%s%s", pname, filesep, fname);
+ // Check whether file exists.
+ if (ret != -1) {
+ struct stat statbuf;
+ return os::stat(buffer, &statbuf) == 0;
+ }
+ return false;
+}
+
+bool os::dll_locate_lib(char *buffer, size_t buflen,
+ const char* pname, const char* fname) {
+ bool retval = false;
+
+ size_t fullfnamelen = strlen(JNI_LIB_PREFIX) + strlen(fname) + strlen(JNI_LIB_SUFFIX);
+ char* fullfname = (char*)NEW_C_HEAP_ARRAY(char, fullfnamelen + 1, mtInternal);
+ if (dll_build_name(fullfname, fullfnamelen + 1, fname)) {
+ const size_t pnamelen = pname ? strlen(pname) : 0;
+
+ if (pnamelen == 0) {
+ // If no path given, use current working directory.
+ const char* p = get_current_directory(buffer, buflen);
+ if (p != NULL) {
+ const size_t plen = strlen(buffer);
+ const char lastchar = buffer[plen - 1];
+ retval = conc_path_file_and_check(buffer, &buffer[plen], buflen - plen,
+ "", lastchar, fullfname);
+ }
+ } else if (strchr(pname, *os::path_separator()) != NULL) {
+ // A list of paths. Search for the path that contains the library.
+ int n;
+ char** pelements = split_path(pname, &n);
+ if (pelements != NULL) {
+ for (int i = 0; i < n; i++) {
+ char* path = pelements[i];
+ // Really shouldn't be NULL, but check can't hurt.
+ size_t plen = (path == NULL) ? 0 : strlen(path);
+ if (plen == 0) {
+ continue; // Skip the empty path values.
+ }
+ const char lastchar = path[plen - 1];
+ retval = conc_path_file_and_check(buffer, buffer, buflen, path, lastchar, fullfname);
+ if (retval) break;
+ }
+ // Release the storage allocated by split_path.
+ for (int i = 0; i < n; i++) {
+ if (pelements[i] != NULL) {
+ FREE_C_HEAP_ARRAY(char, pelements[i]);
+ }
+ }
+ FREE_C_HEAP_ARRAY(char*, pelements);
+ }
+ } else {
+ // A definite path.
+ const char lastchar = pname[pnamelen-1];
+ retval = conc_path_file_and_check(buffer, buffer, buflen, pname, lastchar, fullfname);
+ }
+ }
+
+ FREE_C_HEAP_ARRAY(char*, fullfname);
+ return retval;
+}
// --------------------- sun.misc.Signal (optional) ---------------------
@@ -427,13 +503,13 @@
// Try to load verify dll first. In 1.3 java dll depends on it and is not
// always able to find it when the loading executable is outside the JDK.
// In order to keep working with 1.2 we ignore any loading errors.
- if (dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
+ if (dll_locate_lib(buffer, sizeof(buffer), Arguments::get_dll_dir(),
"verify")) {
dll_load(buffer, ebuf, sizeof(ebuf));
}
// Load java dll
- if (dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
+ if (dll_locate_lib(buffer, sizeof(buffer), Arguments::get_dll_dir(),
"java")) {
_native_java_library = dll_load(buffer, ebuf, sizeof(ebuf));
}
@@ -444,7 +520,7 @@
#if defined(__OpenBSD__)
// Work-around OpenBSD's lack of $ORIGIN support by pre-loading libnet.so
// ignore errors
- if (dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
+ if (dll_locate_lib(buffer, sizeof(buffer), Arguments::get_dll_dir(),
"net")) {
dll_load(buffer, ebuf, sizeof(ebuf));
}
--- a/hotspot/src/share/vm/runtime/os.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/os.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -476,7 +476,6 @@
static frame fetch_frame_from_context(const void* ucVoid);
static frame fetch_frame_from_ucontext(Thread* thread, void* ucVoid);
- static ExtendedPC get_thread_pc(Thread *thread);
static void breakpoint();
static bool start_debugging(char *buf, int buflen);
@@ -541,9 +540,16 @@
static const char* get_temp_directory();
static const char* get_current_directory(char *buf, size_t buflen);
- // Builds a platform-specific full library path given a ld path and lib name
- // Returns true if buffer contains full path to existing file, false otherwise
+ // Builds the platform-specific name of a library.
+ // Returns false if the buffer is too small.
static bool dll_build_name(char* buffer, size_t size,
+ const char* fname);
+
+ // Builds a platform-specific full library path given an ld path and
+ // unadorned library name. Returns true if the buffer contains a full
+ // path to an existing file, false otherwise. If pathname is empty,
+ // uses the path to the current directory.
+ static bool dll_locate_lib(char* buffer, size_t size,
const char* pathname, const char* fname);
// Symbol lookup, find nearest function name; basically it implements
--- a/hotspot/src/share/vm/runtime/sweeper.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -53,7 +53,7 @@
public:
int traversal;
int compile_id;
- jlong traversal_mark;
+ long traversal_mark;
int state;
const char* kind;
address vep;
@@ -62,7 +62,7 @@
void print() {
tty->print_cr("traversal = %d compile_id = %d %s uep = " PTR_FORMAT " vep = "
- PTR_FORMAT " state = %d traversal_mark "JLONG_FORMAT" line = %d",
+ PTR_FORMAT " state = %d traversal_mark %ld line = %d",
traversal,
compile_id,
kind == NULL ? "" : kind,
@@ -629,6 +629,7 @@
} else if (cm->is_not_entrant()) {
// If there are no current activations of this method on the
// stack we can safely convert it to a zombie method
+ OrderAccess::loadload(); // _stack_traversal_mark and _state
if (cm->can_convert_to_zombie()) {
// Clear ICStubs to prevent back patching stubs of zombie or flushed
// nmethods during the next safepoint (see ICStub::finalize).
--- a/hotspot/src/share/vm/runtime/thread.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/thread.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -63,7 +63,6 @@
#include "runtime/commandLineFlagWriteableList.hpp"
#include "runtime/commandLineFlagRangeList.hpp"
#include "runtime/deoptimization.hpp"
-#include "runtime/fprofiler.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/globals.hpp"
#include "runtime/init.hpp"
@@ -748,19 +747,6 @@
}
#endif // PRODUCT
-// Called by flat profiler
-// Callers have already called wait_for_ext_suspend_completion
-// The assertion for that is currently too complex to put here:
-bool JavaThread::profile_last_Java_frame(frame* _fr) {
- bool gotframe = false;
- // self suspension saves needed state.
- if (has_last_Java_frame() && _anchor.walkable()) {
- *_fr = pd_last_frame();
- gotframe = true;
- }
- return gotframe;
-}
-
void Thread::interrupt(Thread* thread) {
debug_only(check_for_dangling_thread_pointer(thread);)
os::interrupt(thread);
@@ -1381,14 +1367,6 @@
while (watcher_thread() != NULL) {
// This wait should make safepoint checks, wait without a timeout,
// and wait as a suspend-equivalent condition.
- //
- // Note: If the FlatProfiler is running, then this thread is waiting
- // for the WatcherThread to terminate and the WatcherThread, via the
- // FlatProfiler task, is waiting for the external suspend request on
- // this thread to complete. wait_for_ext_suspend_completion() will
- // eventually timeout, but that takes time. Making this wait a
- // suspend-equivalent condition solves that timeout problem.
- //
Terminator_lock->wait(!Mutex::_no_safepoint_check_flag, 0,
Mutex::_as_suspend_equivalent_flag);
}
@@ -1505,16 +1483,6 @@
}
#endif // PRODUCT
- set_thread_profiler(NULL);
- if (FlatProfiler::is_active()) {
- // This is where we would decide to either give each thread it's own profiler
- // or use one global one from FlatProfiler,
- // or up to some count of the number of profiled threads, etc.
- ThreadProfiler* pp = new ThreadProfiler();
- pp->engage();
- set_thread_profiler(pp);
- }
-
// Setup safepoint state info for this thread
ThreadSafepointState::create(this);
@@ -1660,7 +1628,6 @@
// All Java related clean up happens in exit
ThreadSafepointState::destroy(this);
- if (_thread_profiler != NULL) delete _thread_profiler;
if (_thread_stat != NULL) delete _thread_stat;
#if INCLUDE_JVMCI
@@ -1775,13 +1742,6 @@
Handle threadObj(this, this->threadObj());
assert(threadObj.not_null(), "Java thread object should be created");
- if (get_thread_profiler() != NULL) {
- get_thread_profiler()->disengage();
- ResourceMark rm;
- get_thread_profiler()->print(get_thread_name());
- }
-
-
// FIXIT: This code should be moved into else part, when reliable 1.2/1.3 check is in place
{
EXCEPTION_MARK;
@@ -1983,12 +1943,6 @@
#endif // INCLUDE_ALL_GCS
void JavaThread::cleanup_failed_attach_current_thread() {
- if (get_thread_profiler() != NULL) {
- get_thread_profiler()->disengage();
- ResourceMark rm;
- get_thread_profiler()->print(get_thread_name());
- }
-
if (active_handles() != NULL) {
JNIHandleBlock* block = active_handles();
set_active_handles(NULL);
@@ -2786,9 +2740,6 @@
// Verify that the deferred card marks have been flushed.
assert(deferred_card_mark().is_empty(), "Should be empty during GC");
- // The ThreadProfiler oops_do is done from FlatProfiler::oops_do
- // since there may be more than one thread using each ThreadProfiler.
-
// Traverse the GCHandles
Thread::oops_do(f, cf);
@@ -3717,14 +3668,6 @@
Thread* THREAD = Thread::current();
- // At this point, the Universe is initialized, but we have not executed
- // any byte code. Now is a good time (the only time) to dump out the
- // internal state of the JVM for sharing.
- if (DumpSharedSpaces) {
- MetaspaceShared::preload_and_dump(CHECK_JNI_ERR);
- ShouldNotReachHere();
- }
-
// Always call even when there are not JVMTI environments yet, since environments
// may be attached late and JVMTI must track phases of VM execution
JvmtiExport::enter_early_start_phase();
@@ -3849,7 +3792,6 @@
}
#endif // INCLUDE_MANAGEMENT
- if (Arguments::has_profile()) FlatProfiler::engage(main_thread, true);
if (MemProfiling) MemProfiler::engage();
StatSampler::engage();
if (CheckJNICalls) JniPeriodicChecker::engage();
@@ -3887,6 +3829,12 @@
#ifdef ASSERT
_vm_complete = true;
#endif
+
+ if (DumpSharedSpaces) {
+ MetaspaceShared::preload_and_dump(CHECK_JNI_ERR);
+ ShouldNotReachHere();
+ }
+
return JNI_OK;
}
@@ -3925,13 +3873,12 @@
}
} else {
// Try to load the agent from the standard dll directory
- if (os::dll_build_name(buffer, sizeof(buffer), Arguments::get_dll_dir(),
+ if (os::dll_locate_lib(buffer, sizeof(buffer), Arguments::get_dll_dir(),
name)) {
library = os::dll_load(buffer, ebuf, sizeof ebuf);
}
- if (library == NULL) { // Try the local directory
- char ns[1] = {0};
- if (os::dll_build_name(buffer, sizeof(buffer), ns, name)) {
+ if (library == NULL) { // Try the library path directory.
+ if (os::dll_build_name(buffer, sizeof(buffer), name)) {
library = os::dll_load(buffer, ebuf, sizeof ebuf);
}
if (library == NULL) {
@@ -4139,7 +4086,7 @@
// + Call before_exit(), prepare for VM exit
// > run VM level shutdown hooks (they are registered through JVM_OnExit(),
// currently the only user of this mechanism is File.deleteOnExit())
-// > stop flat profiler, StatSampler, watcher thread, CMS threads,
+// > stop StatSampler, watcher thread, CMS threads,
// post thread end and vm death events to JVMTI,
// stop signal thread
// + Call JavaThread::exit(), it will:
@@ -4168,14 +4115,6 @@
while (Threads::number_of_non_daemon_threads() > 1)
// This wait should make safepoint checks, wait without a timeout,
// and wait as a suspend-equivalent condition.
- //
- // Note: If the FlatProfiler is running and this thread is waiting
- // for another non-daemon thread to finish, then the FlatProfiler
- // is waiting for the external suspend request on this thread to
- // complete. wait_for_ext_suspend_completion() will eventually
- // timeout, but that takes time. Making this wait a suspend-
- // equivalent condition solves that timeout problem.
- //
Threads_lock->wait(!Mutex::_no_safepoint_check_flag, 0,
Mutex::_as_suspend_equivalent_flag);
}
--- a/hotspot/src/share/vm/runtime/thread.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/thread.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -56,7 +56,6 @@
#endif
class ThreadSafepointState;
-class ThreadProfiler;
class JvmtiThreadState;
class JvmtiGetLoadedClassesClosure;
@@ -1720,23 +1719,6 @@
void deoptimized_wrt_marked_nmethods();
- // Profiling operation (see fprofile.cpp)
- public:
- bool profile_last_Java_frame(frame* fr);
-
- private:
- ThreadProfiler* _thread_profiler;
- private:
- friend class FlatProfiler; // uses both [gs]et_thread_profiler.
- friend class FlatProfilerTask; // uses get_thread_profiler.
- friend class ThreadProfilerMark; // uses get_thread_profiler.
- ThreadProfiler* get_thread_profiler() { return _thread_profiler; }
- ThreadProfiler* set_thread_profiler(ThreadProfiler* tp) {
- ThreadProfiler* result = _thread_profiler;
- _thread_profiler = tp;
- return result;
- }
-
public:
// Returns the running thread as a JavaThread
static inline JavaThread* current();
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -841,7 +841,7 @@
nonstatic_field(nmethod, _verified_entry_point, address) \
nonstatic_field(nmethod, _osr_entry_point, address) \
volatile_nonstatic_field(nmethod, _lock_count, jint) \
- volatile_nonstatic_field(nmethod, _stack_traversal_mark, jlong) \
+ volatile_nonstatic_field(nmethod, _stack_traversal_mark, long) \
nonstatic_field(nmethod, _compile_id, int) \
nonstatic_field(nmethod, _comp_level, int) \
\
--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -414,11 +414,7 @@
}
void SystemGCDCmd::execute(DCmdSource source, TRAPS) {
- if (!DisableExplicitGC) {
- Universe::heap()->collect(GCCause::_dcmd_gc_run);
- } else {
- output()->print_cr("Explicit GC is disabled, no GC has been performed.");
- }
+ Universe::heap()->collect(GCCause::_dcmd_gc_run);
}
void RunFinalizationDCmd::execute(DCmdSource source, TRAPS) {
--- a/hotspot/src/share/vm/utilities/decoder.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/utilities/decoder.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@
#if defined(_WINDOWS)
#include "decoder_windows.hpp"
+ #include "windbghelp.hpp"
#elif defined(__APPLE__)
#include "decoder_machO.hpp"
#elif defined(AIX)
@@ -162,3 +163,9 @@
_shared_decoder = &_do_nothing_decoder;
}
+void Decoder::print_state_on(outputStream* st) {
+#ifdef _WINDOWS
+ WindowsDbgHelp::print_state_on(st);
+#endif
+}
+
--- a/hotspot/src/share/vm/utilities/decoder.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/utilities/decoder.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -29,6 +29,7 @@
#include "memory/allocation.hpp"
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
+#include "utilities/ostream.hpp"
class AbstractDecoder : public CHeapObj<mtInternal> {
public:
@@ -41,7 +42,6 @@
out_of_memory, // out of memory
file_invalid, // invalid elf file
file_not_found, // could not found symbol file (on windows), such as jvm.pdb or jvm.map
- helper_not_found, // could not load dbghelp.dll (Windows only)
helper_func_error, // decoding functions not found (Windows only)
helper_init_error // SymInitialize failed (Windows only)
};
@@ -117,6 +117,9 @@
// shutdown shared instance
static void shutdown();
+
+ static void print_state_on(outputStream* st);
+
protected:
// shared decoder instance, _shared_instance_lock is needed
static AbstractDecoder* get_shared_instance();
--- a/hotspot/src/share/vm/utilities/exceptions.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/utilities/exceptions.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -87,13 +87,9 @@
#endif // ASSERT
if (thread->is_VM_thread()
- || !thread->can_call_java()
- || DumpSharedSpaces ) {
+ || !thread->can_call_java()) {
// We do not care what kind of exception we get for the vm-thread or a thread which
// is compiling. We just install a dummy exception object
- //
- // We also cannot throw a proper exception when dumping, because we cannot run
- // Java bytecodes now. A dummy exception will suffice.
thread->set_pending_exception(Universe::vm_exception(), file, line);
return true;
}
@@ -114,13 +110,9 @@
}
if (thread->is_VM_thread()
- || !thread->can_call_java()
- || DumpSharedSpaces ) {
+ || !thread->can_call_java()) {
// We do not care what kind of exception we get for the vm-thread or a thread which
// is compiling. We just install a dummy exception object
- //
- // We also cannot throw a proper exception when dumping, because we cannot run
- // Java bytecodes now. A dummy exception will suffice.
thread->set_pending_exception(Universe::vm_exception(), file, line);
return true;
}
--- a/hotspot/src/share/vm/utilities/macros.hpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/utilities/macros.hpp Sun Sep 03 14:19:45 2017 +0200
@@ -65,18 +65,6 @@
#define NOT_JVMTI_RETURN_(code) { return code; }
#endif // INCLUDE_JVMTI
-#ifndef INCLUDE_FPROF
-#define INCLUDE_FPROF 1
-#endif
-
-#if INCLUDE_FPROF
-#define NOT_FPROF_RETURN /* next token must be ; */
-#define NOT_FPROF_RETURN_(code) /* next token must be ; */
-#else
-#define NOT_FPROF_RETURN {}
-#define NOT_FPROF_RETURN_(code) { return code; }
-#endif // INCLUDE_FPROF
-
#ifndef INCLUDE_VM_STRUCTS
#define INCLUDE_VM_STRUCTS 1
#endif
--- a/hotspot/src/share/vm/utilities/vmError.cpp Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Sun Sep 03 14:19:45 2017 +0200
@@ -890,6 +890,13 @@
st->cr();
}
+ STEP("printing native decoder state")
+
+ if (_verbose) {
+ Decoder::print_state_on(st);
+ st->cr();
+ }
+
STEP("printing VM options")
if (_verbose) {
--- a/hotspot/test/Makefile Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/test/Makefile Sun Sep 03 14:19:45 2017 +0200
@@ -70,8 +70,8 @@
CONCURRENCY := 12
endif
-# Make sure MaxRAMFraction is high enough to not cause OOM or swapping since we may end up with a lot of JVM's
-JTREG_BASIC_OPTIONS += -vmoption:-XX:MaxRAMFraction=$(shell expr $(CONCURRENCY) \* 4)
+# Make sure MaxRAMPercentage is high enough to not cause OOM or swapping since we may end up with a lot of JVM's
+JTREG_BASIC_OPTIONS += -vmoption:-XX:MaxRAMPercentage=$(shell expr 25 / $(CONCURRENCY))
# Include the common base file with most of the logic
include ../../test/TestCommon.gmk
--- a/hotspot/test/gc/g1/TestGCLogMessages.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/test/gc/g1/TestGCLogMessages.java Sun Sep 03 14:19:45 2017 +0200
@@ -110,7 +110,6 @@
new LogMessageWithLevel("Universe Roots", Level.TRACE),
new LogMessageWithLevel("JNI Handles Roots", Level.TRACE),
new LogMessageWithLevel("ObjectSynchronizer Roots", Level.TRACE),
- new LogMessageWithLevel("FlatProfiler Roots", Level.TRACE),
new LogMessageWithLevel("Management Roots", Level.TRACE),
new LogMessageWithLevel("SystemDictionary Roots", Level.TRACE),
new LogMessageWithLevel("CLDG Roots", Level.TRACE),
--- a/hotspot/test/runtime/CommandLine/FlagWithInvalidValue.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/test/runtime/CommandLine/FlagWithInvalidValue.java Sun Sep 03 14:19:45 2017 +0200
@@ -36,10 +36,10 @@
public class FlagWithInvalidValue {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-XX:MaxRAMFraction=v", "-version");
+ "-XX:MaxRAMPercentage=v", "-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
- output.shouldContain("Improperly specified VM option 'MaxRAMFraction=v'");
+ output.shouldContain("Improperly specified VM option 'MaxRAMPercentage=v'");
output.shouldHaveExitValue(1);
}
}
--- a/hotspot/test/runtime/CommandLine/NonBooleanFlagWithInvalidBooleanPrefix.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/test/runtime/CommandLine/NonBooleanFlagWithInvalidBooleanPrefix.java Sun Sep 03 14:19:45 2017 +0200
@@ -36,17 +36,17 @@
public class NonBooleanFlagWithInvalidBooleanPrefix {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
- "-XX:-MaxRAMFraction=16", "-version");
+ "-XX:-MaxRAMPercentage=1", "-version");
OutputAnalyzer output = new OutputAnalyzer(pb.start());
- output.shouldContain("Unexpected +/- setting in VM option 'MaxRAMFraction=16'");
+ output.shouldContain("Unexpected +/- setting in VM option 'MaxRAMPercentage=1'");
output.shouldHaveExitValue(1);
pb = ProcessTools.createJavaProcessBuilder(
- "-XX:+MaxRAMFraction=16", "-version");
+ "-XX:+MaxRAMPercentage=1", "-version");
output = new OutputAnalyzer(pb.start());
- output.shouldContain("Unexpected +/- setting in VM option 'MaxRAMFraction=16'");
+ output.shouldContain("Unexpected +/- setting in VM option 'MaxRAMPercentage=1'");
output.shouldHaveExitValue(1);
}
--- a/hotspot/test/runtime/CommandLine/TestNullTerminatedFlags.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/test/runtime/CommandLine/TestNullTerminatedFlags.java Sun Sep 03 14:19:45 2017 +0200
@@ -42,7 +42,6 @@
"-green",
"-native",
"-Xrs",
- "-Xprof",
"-Xconcurrentio",
"-Xinternalversion",
"-Xprintflags",
--- a/hotspot/test/runtime/CommandLine/VMDeprecatedOptions.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/test/runtime/CommandLine/VMDeprecatedOptions.java Sun Sep 03 14:19:45 2017 +0200
@@ -43,6 +43,9 @@
{"MaxGCMinorPauseMillis", "1032"},
{"MustCallLoadClassInternal", "false"},
{"UnsyncloadClass", "false"},
+ {"MaxRAMFraction", "8"},
+ {"MinRAMFraction", "2"},
+ {"InitialRAMFraction", "64"},
// deprecated alias flags (see also aliased_jvm_flags):
{"DefaultMaxRAMFraction", "4"},
--- a/hotspot/test/runtime/MinimalVM/Xprof.java Fri Sep 01 14:13:09 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @requires vm.flavor == "minimal"
- * @modules java.base/jdk.internal.misc
- * @library /test/lib
- * @run driver Xprof
- */
-
-import jdk.test.lib.process.OutputAnalyzer;
-import jdk.test.lib.process.ProcessTools;
-
-public class Xprof {
-
- public static void main(String args[]) throws Exception {
- ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-minimal", "-Xprof", "-version");
- new OutputAnalyzer(pb.start())
- .shouldContain("Flat profiling is not supported in this VM.")
- .shouldHaveExitValue(1);
-
- }
-}
--- a/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java Sun Sep 03 14:19:45 2017 +0200
@@ -205,7 +205,11 @@
OutputAnalyzer out = CDSTestUtils.runWithArchive(opts);
CDSTestUtils.checkExec(out, opts, "[class,load] org.omg.CORBA.Context");
if (!CDSTestUtils.isUnableToMap(out)) {
- out.shouldMatch(".*\\[class,load\\] org.omg.CORBA.Context source:.*bootAppend.jar");
+ if (mode.equals("off")) {
+ out.shouldMatch(".*\\[class,load\\] org.omg.CORBA.Context source:.*bootAppend.jar");
+ } else {
+ CDSTestUtils.checkExec(out, opts, "[class,load] org.omg.CORBA.Context source: shared objects file");
+ }
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/NonBootLoaderClasses.java Sun Sep 03 14:19:45 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test NonBootLoaderClasses
+ * @summary Test to ensure platform and app classes are not being archived
+ * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * java.management
+ * @run main NonBootLoaderClasses
+ */
+
+import jdk.test.lib.cds.CDSOptions;
+import jdk.test.lib.cds.CDSTestUtils;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import java.io.File;
+
+public class NonBootLoaderClasses {
+ public static void main(String[] args) throws Exception {
+ final String PLATFORM_CLASS = "jdk/dynalink/DynamicLinker";
+ final String APP_CLASS = "com/sun/tools/javac/Main";
+ String[] classes = {PLATFORM_CLASS, APP_CLASS};
+ String classList =
+ CDSTestUtils.makeClassList(classes).getPath();
+ String archiveName = "NonBootLoaderClasses.jsa";
+ CDSOptions opts = (new CDSOptions())
+ .addPrefix("-XX:ExtraSharedClassListFile=" + classList)
+ .setArchiveName(archiveName);
+ CDSTestUtils.createArchiveAndCheck(opts);
+
+ // Print the shared dictionary and inspect the output
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./" + archiveName,
+ "-XX:+PrintSharedArchiveAndExit", "-XX:+PrintSharedDictionary");
+ OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "print-shared-archive");
+ if (!CDSTestUtils.isUnableToMap(out)) {
+ out.shouldContain("archive is valid")
+ .shouldHaveExitValue(0) // Should report success in error code.
+ .shouldNotContain(PLATFORM_CLASS)
+ .shouldNotContain(APP_CLASS);
+ }
+ }
+}
--- a/hotspot/test/runtime/modules/PatchModule/PatchModuleCDS.java Fri Sep 01 14:13:09 2017 +0000
+++ b/hotspot/test/runtime/modules/PatchModule/PatchModuleCDS.java Sun Sep 03 14:19:45 2017 +0200
@@ -69,7 +69,7 @@
"-XX:+UnlockDiagnosticVMOptions",
"-XX:SharedArchiveFile=" + filename,
"-Xshare:dump",
- "--patch-module=java.base=" + System.getProperty("test.classes"),
+ "--patch-module=java.naming=" + System.getProperty("test.classes"),
"-Xlog:class+path=info",
"-version");
new OutputAnalyzer(pb.start())