Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -591,9 +591,7 @@ public final void decode(EncodedGraph encodedGraph, Iterable<EncodedGraph.Encode
}
}

if (encodedGraph.hasUnsafeAccess()) {
graph.markUnsafeAccess();
}
graph.maybeMarkUnsafeAccess(encodedGraph);
} catch (Throwable ex) {
debug.handle(ex);
}
Expand All @@ -615,9 +613,7 @@ protected void recordGraphElements(EncodedGraph encodedGraph) {
} else {
assert inlinedAssumptions == null : String.format("cannot inline graph (%s) which makes assumptions into a graph (%s) that doesn't", encodedGraph, graph);
}
if (encodedGraph.hasUnsafeAccess()) {
graph.markUnsafeAccess();
}
graph.maybeMarkUnsafeAccess(encodedGraph);
}

protected final LoopScope createInitialLoopScope(MethodScope methodScope, FixedWithNextNode startNode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
import jdk.graal.compiler.nodes.java.MethodCallTargetNode;
import jdk.graal.compiler.nodes.spi.ProfileProvider;
import jdk.graal.compiler.nodes.spi.ResolvedJavaMethodProfileProvider;
import jdk.graal.compiler.nodes.spi.TrackedUnsafeAccess;
import jdk.graal.compiler.nodes.spi.VirtualizableAllocation;
import jdk.graal.compiler.nodes.util.GraphUtil;
import jdk.graal.compiler.options.OptionValues;
Expand Down Expand Up @@ -315,9 +316,23 @@ public StructuredGraph build() {
*/
private final List<ResolvedJavaMethod> methods;

/**
* See {@link #markUnsafeAccess(Class)} for explanation.
*/
private enum UnsafeAccessState {
/**
* A {@link TrackedUnsafeAccess} node has never been added to this graph.
*/
NO_ACCESS,

/**
* A {@link TrackedUnsafeAccess} node was added to this graph at a prior point.
*/
HAS_ACCESS,

/**
* In synthetic methods we disable unsafe access tracking.
*/
DISABLED
}

Expand Down Expand Up @@ -1104,7 +1119,31 @@ public boolean hasUnsafeAccess() {
return hasUnsafeAccess == UnsafeAccessState.HAS_ACCESS;
}

public void markUnsafeAccess() {
/**
* Records that this graph encodes a memory access via the {@code Unsafe} class.
*
* HotSpot requires this information to modify the behavior of its signal handling for compiled
* code that contains an unsafe memory access.
*
* @param nodeClass the type of the node encoding the unsafe access
*/
public void markUnsafeAccess(Class<? extends TrackedUnsafeAccess> nodeClass) {
markUnsafeAccess();
}

public void maybeMarkUnsafeAccess(EncodedGraph graph) {
if (graph.hasUnsafeAccess()) {
markUnsafeAccess();
}
}

public void maybeMarkUnsafeAccess(StructuredGraph graph) {
if (graph.hasUnsafeAccess()) {
markUnsafeAccess();
}
}

private void markUnsafeAccess() {
if (hasUnsafeAccess == UnsafeAccessState.DISABLED) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import jdk.graal.compiler.nodes.memory.OrderedMemoryAccess;
import jdk.graal.compiler.nodes.spi.Canonicalizable;
import jdk.graal.compiler.nodes.spi.CanonicalizerTool;
import jdk.graal.compiler.nodes.spi.TrackedUnsafeAccess;
import jdk.graal.compiler.nodes.type.StampTool;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.JavaConstant;
Expand All @@ -52,7 +53,7 @@
import jdk.vm.ci.meta.ResolvedJavaType;

@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
public abstract class UnsafeAccessNode extends FixedWithNextNode implements Canonicalizable, OrderedMemoryAccess, MemoryAccess {
public abstract class UnsafeAccessNode extends FixedWithNextNode implements Canonicalizable, OrderedMemoryAccess, MemoryAccess, TrackedUnsafeAccess {

public static final NodeClass<UnsafeAccessNode> TYPE = NodeClass.create(UnsafeAccessNode.class);
@Input ValueNode object;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,23 @@
import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_2;
import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_1;

import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.core.common.type.StampFactory;
import jdk.graal.compiler.graph.NodeClass;
import jdk.graal.compiler.nodeinfo.NodeInfo;
import jdk.graal.compiler.nodes.FixedWithNextNode;
import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.memory.MemoryAccess;
import jdk.graal.compiler.nodes.spi.Lowerable;
import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.nodes.spi.TrackedUnsafeAccess;
import jdk.vm.ci.meta.JavaKind;

/**
* Load of a value at a location specified as an absolute address.
*/
@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
public class UnsafeMemoryLoadNode extends FixedWithNextNode implements Lowerable, MemoryAccess {
public class UnsafeMemoryLoadNode extends FixedWithNextNode implements Lowerable, MemoryAccess, TrackedUnsafeAccess {

public static final NodeClass<UnsafeMemoryLoadNode> TYPE = NodeClass.create(UnsafeMemoryLoadNode.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,23 @@
import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_2;
import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_1;

import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.core.common.type.StampFactory;
import jdk.graal.compiler.graph.NodeClass;
import jdk.graal.compiler.nodeinfo.NodeInfo;
import jdk.graal.compiler.nodes.AbstractStateSplit;
import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.memory.SingleMemoryKill;
import jdk.graal.compiler.nodes.spi.Lowerable;
import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.nodes.spi.TrackedUnsafeAccess;
import jdk.vm.ci.meta.JavaKind;

/**
* Store of a value at a location specified as an absolute address.
*/
@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
public class UnsafeMemoryStoreNode extends AbstractStateSplit implements Lowerable, SingleMemoryKill {
public class UnsafeMemoryStoreNode extends AbstractStateSplit implements Lowerable, SingleMemoryKill, TrackedUnsafeAccess {

public static final NodeClass<UnsafeMemoryStoreNode> TYPE = NodeClass.create(UnsafeMemoryStoreNode.class);
@Input protected ValueNode value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,14 @@
import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_8;
import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_8;

import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.core.common.memory.MemoryOrderMode;
import jdk.graal.compiler.core.common.type.FloatStamp;
import jdk.graal.compiler.core.common.type.Stamp;
import jdk.graal.compiler.debug.Assertions;
import jdk.graal.compiler.graph.NodeClass;
import jdk.graal.compiler.nodeinfo.NodeInfo;
import jdk.graal.compiler.nodes.virtual.VirtualArrayNode;
import jdk.graal.compiler.nodes.virtual.VirtualInstanceNode;
import jdk.graal.compiler.nodes.virtual.VirtualObjectNode;
import jdk.graal.compiler.nodes.LogicConstantNode;
import jdk.graal.compiler.nodes.LogicNode;
import jdk.graal.compiler.nodes.NodeView;
Expand All @@ -52,15 +51,17 @@
import jdk.graal.compiler.nodes.memory.OrderedMemoryAccess;
import jdk.graal.compiler.nodes.memory.SingleMemoryKill;
import jdk.graal.compiler.nodes.spi.Lowerable;
import jdk.graal.compiler.nodes.spi.TrackedUnsafeAccess;
import jdk.graal.compiler.nodes.spi.Virtualizable;
import jdk.graal.compiler.nodes.spi.VirtualizerTool;
import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.nodes.virtual.VirtualArrayNode;
import jdk.graal.compiler.nodes.virtual.VirtualInstanceNode;
import jdk.graal.compiler.nodes.virtual.VirtualObjectNode;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaField;

@NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_8, size = SIZE_8)
public abstract class AbstractUnsafeCompareAndSwapNode extends AbstractMemoryCheckpoint implements OrderedMemoryAccess, Lowerable, SingleMemoryKill, Virtualizable {
public abstract class AbstractUnsafeCompareAndSwapNode extends AbstractMemoryCheckpoint implements OrderedMemoryAccess, Lowerable, SingleMemoryKill, Virtualizable, TrackedUnsafeAccess {
public static final NodeClass<AbstractUnsafeCompareAndSwapNode> TYPE = NodeClass.create(AbstractUnsafeCompareAndSwapNode.class);
@Input ValueNode object;
@Input ValueNode offset;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,24 @@
import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_8;
import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_2;

import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.core.common.type.StampFactory;
import jdk.graal.compiler.graph.NodeClass;
import jdk.graal.compiler.nodeinfo.NodeInfo;
import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.memory.AbstractMemoryCheckpoint;
import jdk.graal.compiler.nodes.memory.SingleMemoryKill;
import jdk.graal.compiler.nodes.spi.Lowerable;
import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.nodes.spi.TrackedUnsafeAccess;
import jdk.vm.ci.meta.JavaKind;

/**
* Represents an atomic read-and-add operation like
* {@code sun.misc.Unsafe.getAndAddInt(Object, long, int)}.
*/
@NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_8, size = SIZE_2)
public final class AtomicReadAndAddNode extends AbstractMemoryCheckpoint implements Lowerable, SingleMemoryKill {
public final class AtomicReadAndAddNode extends AbstractMemoryCheckpoint implements Lowerable, SingleMemoryKill, TrackedUnsafeAccess {

public static final NodeClass<AtomicReadAndAddNode> TYPE = NodeClass.create(AtomicReadAndAddNode.class);
@Input ValueNode object;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,24 @@
import static jdk.graal.compiler.nodeinfo.NodeCycles.CYCLES_8;
import static jdk.graal.compiler.nodeinfo.NodeSize.SIZE_2;

import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.core.common.type.StampFactory;
import jdk.graal.compiler.graph.NodeClass;
import jdk.graal.compiler.nodeinfo.NodeInfo;
import jdk.graal.compiler.nodes.ValueNode;
import jdk.graal.compiler.nodes.memory.AbstractMemoryCheckpoint;
import jdk.graal.compiler.nodes.memory.SingleMemoryKill;
import jdk.graal.compiler.nodes.spi.Lowerable;
import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.nodes.spi.TrackedUnsafeAccess;
import jdk.vm.ci.meta.JavaKind;

/**
* Represents an atomic read-and-write operation like
* {@code sun.misc.Unsafe.getAndSetInt(Object, long, int)}.
*/
@NodeInfo(cycles = CYCLES_8, size = SIZE_2)
public final class AtomicReadAndWriteNode extends AbstractMemoryCheckpoint implements Lowerable, SingleMemoryKill {
public final class AtomicReadAndWriteNode extends AbstractMemoryCheckpoint implements Lowerable, SingleMemoryKill, TrackedUnsafeAccess {

public static final NodeClass<AtomicReadAndWriteNode> TYPE = NodeClass.create(AtomicReadAndWriteNode.class);
@Input ValueNode object;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2024, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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 jdk.graal.compiler.nodes.spi;

import jdk.graal.compiler.nodes.StructuredGraph;

/**
* Marker interface for a node that requires {@link StructuredGraph#markUnsafeAccess(Class)} to be
* called prior to being added to a graph.
*/
public interface TrackedUnsafeAccess {
}
Original file line number Diff line number Diff line change
Expand Up @@ -667,9 +667,7 @@ private static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, Fi
// Copy inlined methods from inlinee to caller
graph.updateMethods(inlineGraph);

if (inlineGraph.hasUnsafeAccess()) {
graph.markUnsafeAccess();
}
graph.maybeMarkUnsafeAccess(inlineGraph);
assert inlineGraph.getSpeculationLog() == null ||
inlineGraph.getSpeculationLog() == graph.getSpeculationLog() : "Only the root graph should have a speculation log";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.util.Objects;
import java.util.function.BiFunction;

import jdk.graal.compiler.nodes.spi.TrackedUnsafeAccess;
import org.graalvm.word.LocationIdentity;

import jdk.graal.compiler.api.directives.GraalDirectives;
Expand Down Expand Up @@ -683,7 +684,7 @@ private static void registerUnsafeGetAndOpPlugins(Registration r, boolean isSunM
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) {
// Emits a null-check for the otherwise unused receiver
unsafe.get(true);
createUnsafeAccess(object, b, (obj, loc) -> new AtomicReadAndWriteNode(obj, offset, value, kind, loc));
createUnsafeAccess(object, b, (obj, loc) -> new AtomicReadAndWriteNode(obj, offset, value, kind, loc), AtomicReadAndWriteNode.class);
return true;
}
});
Expand All @@ -694,7 +695,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode delta) {
// Emits a null-check for the otherwise unused receiver
unsafe.get(true);
createUnsafeAccess(object, b, (obj, loc) -> new AtomicReadAndAddNode(obj, offset, delta, kind, loc));
createUnsafeAccess(object, b, (obj, loc) -> new AtomicReadAndAddNode(obj, offset, delta, kind, loc), AtomicReadAndAddNode.class);
return true;
}
});
Expand Down Expand Up @@ -1445,9 +1446,9 @@ private void setAccessNodeResult(FixedWithNextNode node, GraphBuilderContext b)
}
}

protected final void createUnsafeAccess(ValueNode value, GraphBuilderContext b, UnsafeNodeConstructor nodeConstructor) {
protected final void createUnsafeAccess(ValueNode value, GraphBuilderContext b, UnsafeNodeConstructor nodeConstructor, Class<? extends TrackedUnsafeAccess> constructorClass) {
StructuredGraph graph = b.getGraph();
graph.markUnsafeAccess();
graph.markUnsafeAccess(constructorClass);
/* For unsafe access object pointers can only be stored in the heap */
if (unsafeAccessKind == JavaKind.Object) {
ValueNode object = value;
Expand Down Expand Up @@ -1527,7 +1528,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
// Emits a null-check for the otherwise unused receiver
unsafe.get(true);
b.addPush(returnKind, new UnsafeMemoryLoadNode(address, unsafeAccessKind, OFF_HEAP_LOCATION));
b.getGraph().markUnsafeAccess();
b.getGraph().markUnsafeAccess(UnsafeMemoryLoadNode.class);
return true;
}

Expand All @@ -1543,7 +1544,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
unsafe.get(true);
// Note that non-ordered raw accesses can be turned into floatable field accesses.
UnsafeNodeConstructor unsafeNodeConstructor = (obj, loc) -> new RawLoadNode(obj, offset, unsafeAccessKind, loc, memoryOrder);
createUnsafeAccess(object, b, unsafeNodeConstructor);
createUnsafeAccess(object, b, unsafeNodeConstructor, RawLoadNode.class);
return true;
}
}
Expand All @@ -1567,7 +1568,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
unsafe.get(true);
ValueNode maskedValue = b.maskSubWordValue(value, unsafeAccessKind);
b.add(new UnsafeMemoryStoreNode(address, maskedValue, unsafeAccessKind, OFF_HEAP_LOCATION));
b.getGraph().markUnsafeAccess();
b.getGraph().markUnsafeAccess(UnsafeMemoryStoreNode.class);
return true;
}

Expand All @@ -1582,7 +1583,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
// Emits a null-check for the otherwise unused receiver
unsafe.get(true);
ValueNode maskedValue = b.maskSubWordValue(value, unsafeAccessKind);
createUnsafeAccess(object, b, (obj, loc) -> new RawStoreNode(obj, offset, maskedValue, unsafeAccessKind, loc, true, memoryOrder));
createUnsafeAccess(object, b, (obj, loc) -> new RawStoreNode(obj, offset, maskedValue, unsafeAccessKind, loc, true, memoryOrder), RawStoreNode.class);
return true;
}
}
Expand All @@ -1603,9 +1604,9 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
// Emits a null-check for the otherwise unused receiver
unsafe.get(true);
if (isLogic) {
createUnsafeAccess(object, b, (obj, loc) -> new UnsafeCompareAndSwapNode(obj, offset, expected, newValue, unsafeAccessKind, loc, memoryOrder));
createUnsafeAccess(object, b, (obj, loc) -> new UnsafeCompareAndSwapNode(obj, offset, expected, newValue, unsafeAccessKind, loc, memoryOrder), UnsafeCompareAndSwapNode.class);
} else {
createUnsafeAccess(object, b, (obj, loc) -> new UnsafeCompareAndExchangeNode(obj, offset, expected, newValue, unsafeAccessKind, loc, memoryOrder));
createUnsafeAccess(object, b, (obj, loc) -> new UnsafeCompareAndExchangeNode(obj, offset, expected, newValue, unsafeAccessKind, loc, memoryOrder), UnsafeCompareAndExchangeNode.class);
}
return true;
}
Expand Down
Loading