This commit is contained in:
Jesper Wilhelmsson 2017-09-03 14:19:45 +02:00
commit 6cdc8d381f
137 changed files with 2095 additions and 3599 deletions

View File

@ -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 @@ ifneq ($(call check-jvm-feature, jvmci), true)
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

View File

@ -3630,6 +3630,12 @@ void MacroAssembler::store_heap_oop_null(Address dst) {
}
#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 @@ void MacroAssembler::g1_write_barrier_pre(Register obj,
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 @@ void MacroAssembler::g1_write_barrier_pre(Register obj,
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()));

View File

@ -2067,7 +2067,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
__ g1_write_barrier_pre(noreg /* obj */,
r0 /* pre_val */,
rthread /* thread */,
rscratch1 /* tmp */,
rscratch2 /* tmp */,
true /* tosca_live */,
true /* expand_call */);
}

View File

@ -170,7 +170,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm,
// 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);

View File

@ -292,7 +292,7 @@ void MacroAssembler::verify_thread() {
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 @@ void MacroAssembler::reset_last_Java_frame(void) {
#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 @@ void MacroAssembler::set_vm_result(Register oop_result) {
# 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();

View File

@ -2928,7 +2928,7 @@ void TemplateTable::invokevirtual(int byte_no) {
__ 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);
}

View File

@ -187,11 +187,10 @@ public final class BinaryContainer implements SymbolTable {
{"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::_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"},
{"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"},
@ -478,8 +477,8 @@ public final class BinaryContainer implements SymbolTable {
}
/**
* 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 @@ public final class BinaryContainer implements SymbolTable {
}
/**
* 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 @@ public final class BinaryContainer implements SymbolTable {
}
/**
* 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

View File

@ -27,6 +27,8 @@ import java.util.ListIterator;
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 @@ final class AOTBackend {
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);

View File

@ -57,7 +57,9 @@ public @interface ClassSubstitution {
/**
* 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;
}

View File

@ -90,7 +90,7 @@ public abstract class AssemblerTest extends GraalTest {
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);

View File

@ -33,6 +33,7 @@ import java.util.Collections;
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 @@ public class CompilationResult {
private final String name;
private final CompilationIdentifier compilationId;
/**
* The buffer containing the emitted machine code.
*/
@ -222,21 +225,26 @@ public class CompilationResult {
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 @@ public class CompilationResult {
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 @@ public class CompilationResult {
return name;
}
public CompilationIdentifier getCompilationId() {
return compilationId;
}
public void setHasUnsafeAccess(boolean hasUnsafeAccess) {
checkOpen();
this.hasUnsafeAccess = hasUnsafeAccess;

View File

@ -949,7 +949,7 @@ public abstract class GraalCompilerTest extends GraalTest {
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 @@ public abstract class GraalCompilerTest extends GraalTest {
*/
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);
}
/**

View File

@ -64,7 +64,7 @@ public class InfopointReasonTest extends GraalCompilerTest {
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 @@ public class InfopointReasonTest extends GraalCompilerTest {
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);

View File

@ -123,7 +123,7 @@ public class InvokeGraal {
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. */

View File

@ -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());
}
}

View File

@ -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 @@ public final class NodeBitMap implements NodeIterable<Node> {
}
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 final class NodeBitMap implements NodeIterable<Node> {
}
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 final class NodeBitMap implements NodeIterable<Node> {
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 @@ public final class NodeBitMap implements NodeIterable<Node> {
}
}
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 @@ public final class NodeBitMap implements NodeIterable<Node> {
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;
}

View File

@ -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()));
}
}
}

View File

@ -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;
}
}

View File

@ -207,7 +207,6 @@ public class CheckGraalIntrinsics extends GraalTest {
"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 @@ public class CheckGraalIntrinsics extends GraalTest {
"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",

View File

@ -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);
}
}

View File

@ -64,9 +64,9 @@ import org.graalvm.compiler.options.OptionType;
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;
@ -257,6 +257,18 @@ public abstract class HotSpotBackend extends Backend implements FrameMap.Referen
@NodeIntrinsic(ForeignCallNode.class)
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
*/

View File

@ -198,7 +198,7 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler {
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);
}

View File

@ -111,6 +111,7 @@ import jdk.vm.ci.meta.JavaConstant;
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 @@ public class HotSpotGraphBuilderPlugins {
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 @@ public class HotSpotGraphBuilderPlugins {
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");

View File

@ -51,6 +51,7 @@ import static org.graalvm.compiler.hotspot.HotSpotBackend.SHA2_IMPL_COMPRESS;
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 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall
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));
}

View File

@ -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);
}
}

View File

@ -216,8 +216,9 @@ public abstract class Stub {
@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;

View File

@ -365,10 +365,6 @@ final class TraceInterval extends IntervalHint {
return intTo;
}
int numUsePositions() {
return numUsePos();
}
public void setLocationHint(IntervalHint interval) {
locationHint = interval;
}
@ -452,6 +448,10 @@ final class TraceInterval extends IntervalHint {
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;

View File

@ -541,16 +541,23 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA
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. */

View File

@ -153,7 +153,7 @@ public final class TraceLinearScanPhase extends TraceAllocationPhase<TraceAlloca
@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>() {

View File

@ -319,7 +319,7 @@ public abstract class GraalCompilerState {
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);
}
/**

View File

@ -209,7 +209,6 @@ public class GraphEncoder {
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 @@ public class GraphEncoder {
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 @@ public class GraphEncoder {
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 @@ public class GraphEncoder {
} 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);
}
}

View File

@ -37,6 +37,7 @@ import java.util.List;
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 @@ public class CFGPrinterObserver implements DebugDumpHandler {
private CFGPrinter cfgPrinter;
private File cfgFile;
private JavaMethod curMethod;
private CompilationIdentifier curCompilation;
private List<String> curDecorators = Collections.emptyList();
@Override
@ -92,6 +94,7 @@ public class CFGPrinterObserver implements DebugDumpHandler {
*/
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 @@ public class CFGPrinterObserver implements DebugDumpHandler {
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 @@ public class CFGPrinterObserver implements DebugDumpHandler {
cfgPrinter = null;
curDecorators = Collections.emptyList();
curMethod = null;
curCompilation = null;
}
}

View File

@ -31,6 +31,7 @@ import java.util.ArrayList;
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 @@ public class CompilationPrinter implements Closeable {
/**
* 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");
}

View File

@ -95,10 +95,13 @@ public final class ClassSubstitutionVerifier extends AbstractVerifier {
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;
}

View File

@ -707,10 +707,22 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
}
}
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 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
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();

View File

@ -1185,62 +1185,6 @@ const char* os::dll_file_extension() { return ".so"; }
// 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::get_summary_cpu_info(char* buf, size_t buflen) {
}
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 @@ void os::hint_no_preempt() {}
////////////////////////////////////////////////////////////////////////////////
// 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 @@ void os::hint_no_preempt() {}
//
// 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 @@ void os::SuspendedThreadTask::internal_do_task() {
}
}
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

View File

@ -1172,13 +1172,6 @@ int os::current_process_id() {
// 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() {
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 @@ void os::hint_no_preempt() {}
////////////////////////////////////////////////////////////////////////////////
// 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 @@ void os::hint_no_preempt() {}
//
// 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 @@ void os::SuspendedThreadTask::internal_do_task() {
}
}
///
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

View File

@ -1419,53 +1419,6 @@ static bool file_exists(const char* filename) {
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 @@ void os::hint_no_preempt() {}
////////////////////////////////////////////////////////////////////////////////
// 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 @@ void os::hint_no_preempt() {}
//
// 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 @@ void os::SuspendedThreadTask::internal_do_task() {
}
}
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

View File

@ -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>

View File

@ -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;

View File

@ -1356,60 +1356,6 @@ const char* os::dll_file_extension() { return ".so"; }
// 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 @@ void os::hint_no_preempt() {
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 void suspend_save_context(OSThread *osthread, ucontext_t* context) {
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 @@ void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) {
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 @@ void os::SuspendedThreadTask::internal_do_task() {
}
}
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,

View File

@ -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 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;
}
}
// 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);
}
// 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);
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);
}
// 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");
}
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;
}
}
// 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);
}
// 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);
}
}
}
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::can_decode_C_frame_in_vm() const {
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::decode(address addr, char *buf, int buflen, int* offset, co
}
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

View File

@ -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 @@ private:
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

View File

@ -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::check_dump_limit(char* buffer, size_t buffsz) {
}
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 @@ void os::abort(bool dump_core, void* siginfo, const void* context) {
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 @@ void os::abort(bool dump_core, void* siginfo, const void* context) {
// 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 @@ const char* os::get_temp_directory() {
}
}
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 @@ bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
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(); }

View File

@ -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();
}

View File

@ -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

View File

@ -106,8 +106,8 @@ struct Atomic::PlatformAdd
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 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
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;

View File

@ -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

View File

@ -184,8 +184,8 @@ struct Atomic::PlatformAdd
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 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
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 @@ inline T Atomic::PlatformCmpxchg<4>::operator()(T exchange_value,
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 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
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);
}

View File

@ -104,8 +104,8 @@ struct Atomic::PlatformAdd
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 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
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;

View File

@ -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

View File

@ -92,9 +92,9 @@ struct Atomic::PlatformAdd
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 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
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;

View File

@ -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

View File

@ -62,8 +62,8 @@ struct Atomic::PlatformAdd
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 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
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(

View File

@ -178,8 +178,8 @@ struct Atomic::PlatformAdd
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 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) co
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);
}

View File

@ -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 @@ bool os::platform_print_native_stack(outputStream* st, const void* context,
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;

View File

@ -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

View File

@ -478,6 +478,8 @@ void AOTCodeHeap::link_stub_routines_symbols() {
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);

View File

@ -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::_jrt_entry = NULL;
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 @@ const char* ClassLoader::package_from_name(const char* const class_name, bool* b
// 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 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
#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 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
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 @@ void ClassLoader::load_zip_library() {
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 @@ void ClassLoader::load_jimage_library() {
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 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
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 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
// 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 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
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 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
}
if (NULL == stream) {
if (DumpSharedSpaces) {
tty->print_cr("Preload Warning: Cannot find %s", class_name);
}
return NULL;
}
@ -1548,6 +1553,100 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
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 @@ void ClassLoader::initialize() {
#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()
}

View File

@ -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 @@ typedef struct {
jlong pos; /* position of LOC header (if negative) or data */
} jzentry;
class ClassPathZipEntry: public ClassPathEntry {
enum {
_unknown = 0,
@ -249,6 +250,10 @@ class ClassLoader: AllStatic {
// 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 @@ class ClassLoader: AllStatic {
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 @@ class ClassLoader: AllStatic {
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);

View File

@ -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 @@ OopHandle ClassLoaderData::add_handle(Handle h) {
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) {

View File

@ -364,6 +364,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
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);

View File

@ -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 @@ public:
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 @@ public:
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

View File

@ -85,6 +85,7 @@ DictionaryEntry* Dictionary::new_entry(unsigned int hash, InstanceKlass* klass)
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 @@ bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
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 @@ bool DictionaryEntry::contains_protection_domain(oop protection_domain) const {
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 @@ void DictionaryEntry::add_protection_domain(Dictionary* dict, Handle protection_
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 @@ void Dictionary::reorder_dictionary_for_sharing() {
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);
}

View File

@ -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 @@ class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
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 @@ public:
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 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
// 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 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
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 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
}
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 @@ class DictionaryEntry : public HashtableEntry<InstanceKlass*, mtClass> {
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 SymbolPropertyEntry : public HashtableEntry<Symbol*, mtSymbol> {
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 @@ public:
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

View File

@ -70,11 +70,25 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
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 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
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 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
p->length = len;
memcpy(p->data, bytes, len);
result->set_archived_class_data(p);
#endif // INCLUDE_JVMTI
}
#endif
#endif // INCLUDE_CDS
return result;
}

View File

@ -729,7 +729,6 @@ bool StringTable::copy_shared_string(GrowableArray<MemRegion> *string_space,
}
G1CollectedHeap::heap()->end_archive_alloc_range(string_space, os::vm_allocation_granularity());
assert(string_space->length() <= 2, "sanity");
return true;
}

View File

@ -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 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
// 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 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
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 @@ InstanceKlass* SystemDictionary::parse_stream(Symbol* class_name,
// 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 @@ InstanceKlass* SystemDictionary::resolve_from_stream(Symbol* class_name,
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* SystemDictionary::resolve_from_stream(Symbol* class_name,
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 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
"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 @@ bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
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 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
}
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 @@ InstanceKlass* SystemDictionary::load_instance_class(Symbol* class_name, Handle
}
}
} 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 @@ void SystemDictionary::methods_do(void f(Method*)) {
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 @@ int SystemDictionaryDCmd::num_arguments() {
}
}
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) {

View File

@ -385,6 +385,7 @@ public:
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 @@ public:
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);

View File

@ -1220,7 +1220,7 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
// for stack scanning.
if (state == not_entrant) {
mark_as_seen_on_stack();
OrderAccess::storestore();
OrderAccess::storestore(); // _stack_traversal_mark and _state
}
// Change state

View File

@ -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 @@ class nmethod : public CompiledMethod {
// 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:
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);

View File

@ -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 @@ class decode_env {
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 @@ class decode_env {
_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 @@ class decode_env {
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 @@ void Disassembler::decode(nmethod* nm, outputStream* st) {
#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());

View File

@ -1719,7 +1719,6 @@ jint G1CollectedHeap::initialize() {
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),

View File

@ -54,7 +54,6 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
_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):");

View File

@ -49,7 +49,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
UniverseRoots,
JNIRoots,
ObjectSynchronizerRoots,
FlatProfilerRoots,
ManagementRoots,
SystemDictionaryRoots,
CLDGRoots,

View File

@ -62,7 +62,7 @@ public:
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()));
}

View File

@ -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"

View File

@ -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"
@ -271,13 +270,6 @@ void G1RootProcessor::process_vm_roots(G1RootClosures* closures,
}
}
{
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)) {

View File

@ -57,7 +57,6 @@ class G1RootProcessor : public StackObj {
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,

View File

@ -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 @@ void MarkFromRootsTask::do_it(GCTaskManager* manager, uint which) {
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;

View File

@ -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 @@ class MarkFromRootsTask : public GCTask {
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;

View File

@ -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 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
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 @@ void PSMarkSweep::mark_sweep_phase3() {
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());

View File

@ -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 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
// 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 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) {
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);

View File

@ -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 @@ bool PSScavenge::invoke_no_policy() {
// 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));

View File

@ -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 @@ void ScavengeRootsTask::do_it(GCTaskManager* manager, uint which) {
ObjectSynchronizer::oops_do(&roots_closure);
break;
case flat_profiler:
FlatProfiler::oops_do(&roots_closure);
break;
case system_dictionary:
SystemDictionary::oops_do(&roots_closure);
break;

View File

@ -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 @@ class ScavengeRootsTask : public GCTask {
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;

View File

@ -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"

View File

@ -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 @@ enum GCH_strong_roots_tasks {
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 @@ void GenCollectedHeap::process_roots(StrongRootsScope* scope,
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);
}

View File

@ -109,6 +109,11 @@ void Rewriter::make_constant_pool_cache(TRAPS) {
MetadataFactory::free_metadata(loader_data, cache);
_pool->set_cache(NULL); // so the verifier isn't confused
}
DEBUG_ONLY(
if (DumpSharedSpaces) {
cache->verify_just_initialized();
})
}

View File

@ -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) \

View File

@ -275,7 +275,8 @@ private:
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

View File

@ -374,25 +374,63 @@ address MetaspaceShared::cds_i2i_entry_code_buffers(size_t total_size) {
// 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 @@ static void relocate_cached_class_file() {
}
}
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 @@ public:
}
memcpy(p, obj, bytes);
bool isnew = _new_loc_table->put(obj, (address)p);
assert(isnew, "must be");
log_trace(cds)("Copy: " PTR_FORMAT " ==> " PTR_FORMAT " %d", p2i(obj), p2i(p), bytes);
assert(isnew, "must be");
_alloc_stats->record(ref->msotype(), int(newtop - oldtop), read_only);
if (ref->msotype() == MetaspaceObj::SymbolType) {
@ -1151,6 +1200,9 @@ char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
// 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 @@ void VM_PopulateDumpSharedSpace::doit() {
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 @@ void VM_PopulateDumpSharedSpace::doit() {
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 @@ void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) {
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 @@ void MetaspaceShared::preload_and_dump(TRAPS) {
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 @@ int MetaspaceShared::preload_classes(const char* class_list_path, TRAPS) {
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;

View File

@ -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"

View File

@ -187,12 +187,29 @@ void ArrayKlass::metaspace_pointers_do(MetaspaceClosure* it) {
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

View File

@ -130,6 +130,7 @@ class ArrayKlass: public Klass {
// 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

View File

@ -89,8 +89,6 @@ ConstantPool::ConstantPool(Array<u1>* tags) :
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 @@ void ConstantPool::archive_resolved_references(Thread* THREAD) {
}
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 @@ void ConstantPool::archive_resolved_references(Thread* THREAD) {
// 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 @@ void ConstantPool::remove_unshareable_info() {
// 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) {

View File

@ -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 @@ void ConstantPoolCacheEntry::initialize_entry(int index) {
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::initialize(const intArray& inverse_index_map,
}
}
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.");

View File

@ -393,6 +393,9 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
// 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 @@ class ConstantPoolCache: public MetaspaceObj {
// 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 @@ class ConstantPoolCache: public MetaspaceObj {
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

View File

@ -747,10 +747,10 @@ void InstanceKlass::initialize_impl(TRAPS) {
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 @@ void InstanceKlass::remove_unshareable_info() {
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 @@ void InstanceKlass::remove_unshareable_info() {
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 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
// 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.

View File

@ -327,8 +327,6 @@ class InstanceKlass: public Klass {
}
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 @@ private:
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

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